如果我有一个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 ++标签。
答案 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 ++ - 请注意,例如,您必须跳过几个额外的箍才能使new
和delete
可用 - 尽管我看到它完成了。惯用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()
可以用来调整结构的大小,但它会使结构的旧指针无效,所以请确保你没有保留它的额外副本(比如将它传递给库)。