如何初始化作为struct typedef一部分的数组?

时间:2010-11-05 17:47:28

标签: c++ c

如果我有一个struct的typedef

typedef struct 
{
char    SmType;
char    SRes;
float   SParm;
float   EParm;
WORD    Count;
char    Flags;
char    unused;
GPOINT2 Nodes[];
} GPATH2;

并且它包含一个未初始化的数组,如何创建这种类型的实例,以便在节点[]中保存4个值?

编辑:这属于使用Assembler编写的程序的API。我想只要内存中的底层数据相同,更改结构定义的答案就可以工作,但如果底层内存不同则不行。汇编语言应用程序不使用此定义....但....使用它的C程序可以创建汇编语言应用程序可以“读取”的GPATH2元素。

创建GPATH2实例后,我可以调整Nodes []的大小吗?

注意:我会用直接的C标签放置它,但只有一个C ++标签。

5 个答案:

答案 0 :(得分:3)

如果是固定大小写:

typedef struct 
{
char    SmType;
char    SRes;
float   SParm;
float   EParm;
WORD    Count;
char    Flags;
char    unused;
GPOINT2 Nodes[4];
} GPATH2;

如果没有修复,则将声明更改为

GPOINT2* Nodes;

创建后或在构造函数中执行

Nodes = new GPOINT2[size];

如果要调整大小,则应使用vector<GPOINT2>,因为无法调整数组大小,只能创建新数组。如果您决定这样做,请不要忘记删除上一个。

在c ++中也不需要typedef,你可以写

struct GPATH2
{
char    SmType;
char    SRes;
float   SParm;
float   EParm;
WORD    Count;
char    Flags;
char    unused;
GPOINT2 Nodes[4];
};

答案 1 :(得分:3)

这似乎是一个被称为“struct hack”的C99成语。您不能(在标准C99中;某些编译器具有允许它的扩展名)声明具有此类型的变量,但您可以声明指向它的指针。您必须使用malloc分配此类型的对象,为适当数量的数组元素提供额外的空间。如果没有任何东西保存指向数组元素的指针,则可以使用realloc调整数组大小。

需要与C89向后兼容的代码需要使用

GPOINT2 Nodes[1];

作为最后一个成员,并在分配时注意这一点。

这非常不是惯用的C ++ - 请注意,例如,您必须跳过几个额外的箍才能使newdelete可用 - 尽管我看到它完成了。惯用C ++将使用vector<GPOINT2>作为结构的最后一个成员。

答案 2 :(得分:3)

如果您真的想要,可以使用C和C ++的混蛋:

#include <new>
#include <cstdlib>

#include "definition_of_GPATH2.h"

using namespace std;

int main(void)
{
    int i;
    /* Allocate raw memory buffer */
    void * raw_buffer = calloc(1, sizeof(GPATH2) + 4 * sizeof(GPOINT2));
    /* Initialize struct with placement-new */
    GPATH2 * path = new (raw_buffer) GPATH2;

    path->Count = 4;
    for ( i = 0 ; i < 4 ; i++ )
    {
        path->Nodes[i].x = rand();
        path->Nodes[i].y = rand();
    }

    /* Resize raw buffer */
    raw_buffer = realloc(raw_buffer, sizeof(GPATH2) + 8 * sizeof(GPOINT2));

    /* 'path' still points to the old buffer that might have been free'd 
     * by realloc, so it has to be re-initialized
     * realloc copies old memory contents, so I am not certain this would
     * work with a proper object that actaully does something in the 
     * constructor
     */
    path = new (raw_buffer) GPATH2;

    /* now we can write more elements of array */
    path->Count = 5;
    path->Nodes[4].x = rand();
    path->Nodes[4].y = rand();

    /* Because this is allocated with malloc/realloc, free it with free
     * rather than delete.
     * If 'path' was a proper object rather than a struct, you should
     * call the destructor manually first.
     */
    free(raw_buffer);

    return 0;
}

当然,正如其他人所观察到的那样,它不是惯用的C ++,但如果结构是遗留代码的一部分,那么它可能是最直接的选择。

上述样本程序的正确性仅使用valgrind使用结构的虚拟定义进行检查,您的里程可能会有所不同。

答案 3 :(得分:1)

未知大小的数组作为C ++数据成员无效。它们在C99中有效,您的编译器可能会将C99支持与C ++混合使用。

你在C ++中可以做的是1)给它一个大小,2)使用向量或其他容器,或者3)抛弃自动(局部变量)和普通动态存储,以便明确地控制分配。第三个在C ++中特别麻烦,特别是对于非POD,但可能;例如:

struct A {
  int const size;
  char data[1];

  ~A() {
    // if data was of non-POD type, we'd destruct data[1] to data[size-1] here
  }

  static auto_ptr<A> create(int size) {
    // because new is used, auto_ptr's use of delete is fine
    // consider another smart pointer type that allows specifying a deleter
    A *p = ::operator new(sizeof(A) + (size - 1) * sizeof(char));
    try {  // not necessary in our case, but is if A's ctor can throw
      new(p) A(size);
    }
    catch (...) {
      ::operator delete(p);
      throw;
    }
    return auto_ptr<A>(p);
  }

private:
  A(int size) : size (size) {
    // if data was of non-POD type, we'd construct here, being very careful
    // of exception safety
  }

  A(A const &other);             // be careful if you define these,
  A& operator=(A const &other);  // but it likely makes sense to forbid them

  void* operator new(size_t size);    // doesn't prevent all erroneous uses,
  void* operator new[](size_t size);  // but this is a start
};

请注意,您不能信任sizeof(A)代码中的任何其他位置,并且使用大小为1的数组可以保证对齐(当类型不是char时很重要)。

答案 4 :(得分:1)

这种类型的结构在堆栈上并不是很容易使用,你必须对它进行malloc。重要的是要知道sizeof(GPATH2)不包括尾随数组。所以要创建一个,你会做这样的事情:

GPATH2 *somePath;
size_t numPoints;

numPoints = 4;
somePath = malloc(sizeof(GPATH2) + numPoints*sizeof(GPOINT2));

我猜测GPATH2.Count是Nodes数组中元素的数量,因此如果由您来初始化,请确保在某个时刻设置somePath->Count = numPoints;。如果我错了,并且使用的约定是null终止数组,那么你会做一些不同的事情:

somePath = malloc(sizeof(GPATH2) + (numPoints+1)*sizeof(GPOINT2));
somePath->Nodes[numPoints] = Some_Sentinel_Value;

确保您知道库使用哪种约定。

正如其他人提到的那样,realloc()可以用来调整结构的大小,但它会使结构的旧指针无效,所以请确保你没有保留它的额外副本(比如将它传递给库)。