我的程序会经常将数据包写入磁盘(fwrite()),并通过以太网发送(send())。数据包按如下结构组织:
struct PacketStruct{
uint32_t Type;
uint8_t * DataPtr;
uint32_t Length;
};
内存是动态分配的,指针分配给PacketStruct.DataPtr。
我的问题是,我想使用另一个结构来组织DataPtr最终指向的数据。例如:
struct MyStruct{
uint32_t A;
uint8_t B;
uint32_t C;
};
然后:
NewPacket = malloc( sizeof(struct PacketStruct) );
NewStruct = malloc( sizeof(struct MyStruct) );
NewStruct->A = 1;
NewStruct->B = 2;
NewStruct->C = 3;
如果我这样做:
NewPacket->DataPtr = (uint8_t *) NewStruct;
NewPacket->Length = sizeof( struct MyStruct);
当我这样做时,我是否会遇到结构填充等问题:
fwrite( (void *) NewPacket->DataPtr, 1, (size_t) NewPacket->Length, fout);
答案 0 :(得分:0)
这取决于你对“问题”的意思。以下是我看到的潜在陷阱:
1)struct MyStruct
可能包含任何成员之后的填充(可能会在B
之后)。此填充所涵盖的内存不会由malloc
或您的赋值语句初始化。如果您改为使用calloc
,则这些区域将初始化为0。
2)如果你需要从文件中读回结构,它将在相同的实现中工作(成员的对齐是实现定义的)。但是一旦你更改了体系结构,编译器,甚至编译器选项,你就不会回读你所写的内容。
3)使用强制转换可以防止编译器进行任何可能捕获错误的类型检查。如果您可以控制struct PacketStruct
的定义,请考虑使用union
的{{1}}种可能类型。这允许您准确指定您期望的类型,在您关心字节时将数据视为DataPtr
,将其视为一个时将其视为uint8_t
。
4)更多的挑剔,但是:你不需要调用struct MyStruct
的演员表,如果这些字段的定义稍后改变,理论上可以隐藏错误。