如何在C/C++中填充struct paddings?
How to fill in struct paddings in C/C++?
假设我有以下结构:
typedef struct {
int mID;
struct in_addr mIP;
size_t dataSize;
// Another structure
fairness_structure str;
bool ack;
bool stability;
bool stop_message;
}HeaderType;
如您所知,结构的大小会因其对齐方式而异。如何用一些数据填充字段之间的填充,比如用零?
只需用memset初始化结构,padding也会被填充。
memset(&mystruct, 0, sizeof(HeaderType));
如果你真的只想填充焊盘,你可以将指针转换为 char*
并进行算术运算。但在这种情况下,您必须知道编译器如何填充结构,或使用 #pragma pack
自行强制执行。
您可以使用 offsetof() 宏来获取结构成员的偏移量。
char *off = (char *)&mystruct + offsetof(HeaderType, ack);
char *pad_start = off + sizeof(mystruct.ack);
char *pad_end = (char *)&mystruct + offsetof(HeaderType, stability);
控制填充位和字节的内容似乎不是很有用。但是,如果您使用单个 write
或 fwrite
调用将结构的内容写入文件,您可能会关心填充并且可能希望确保它们具有一致的值,最好是 0次。当您从文件中读回内容时,这并不重要,但为了使文件内容可预测和可重现。正是由于这个原因,一些开发工具会在目标文件或可执行文件中生成不可预测的内容,这使得从源代码重建和检查签名变得非常困难。
因此,如果您真的需要这个,您需要一个简单且便携的方法。
坏消息是 C 标准对此没有通用的解决方案。
标准对填充字节和位的内容的唯一保证是针对静态存储的未初始化结构。在这种情况下(在托管环境中),填充保证为零。实际上,初始化结构也是如此,因为编译器编写者这样做很简单。
具有自动存储功能的本地结构呢?如果它们未被初始化,则字段和填充内容都是不确定的。如果你只是用 memset(&s, 0, sizeof(s))
清除字节,填充将被清除,你可以开始修改结构成员......再次是坏消息:C 标准描述为 未指定的行为 在结构或联合中存储值时填充字节的值(6.2.6.1)。
换句话说,在结构成员中存储值会对填充位和字节的内容产生副作用。允许编译器生成执行此操作的代码,这样做可能更有效。
Marek 描述的方法超出了简单 memset
使用起来非常麻烦,尤其是当您有位域时。实际上,在手动初始化字段之前清除结构似乎是实现该目的的最简单方法,而且我还没有看到编译器利用标准对填充字节的宽大处理。如果按值传递结构,则所有赌注都将关闭,因为编译器可能生成不复制填充的代码。
作为一个结论:如果你使用局部结构,在使用前用memset
清除它们并且不要按值传递它们。没有保证填充将保持 0 值,但这是你能做的最好的。
假设我有以下结构:
typedef struct {
int mID;
struct in_addr mIP;
size_t dataSize;
// Another structure
fairness_structure str;
bool ack;
bool stability;
bool stop_message;
}HeaderType;
如您所知,结构的大小会因其对齐方式而异。如何用一些数据填充字段之间的填充,比如用零?
只需用memset初始化结构,padding也会被填充。
memset(&mystruct, 0, sizeof(HeaderType));
如果你真的只想填充焊盘,你可以将指针转换为 char*
并进行算术运算。但在这种情况下,您必须知道编译器如何填充结构,或使用 #pragma pack
自行强制执行。
您可以使用 offsetof() 宏来获取结构成员的偏移量。
char *off = (char *)&mystruct + offsetof(HeaderType, ack);
char *pad_start = off + sizeof(mystruct.ack);
char *pad_end = (char *)&mystruct + offsetof(HeaderType, stability);
控制填充位和字节的内容似乎不是很有用。但是,如果您使用单个 write
或 fwrite
调用将结构的内容写入文件,您可能会关心填充并且可能希望确保它们具有一致的值,最好是 0次。当您从文件中读回内容时,这并不重要,但为了使文件内容可预测和可重现。正是由于这个原因,一些开发工具会在目标文件或可执行文件中生成不可预测的内容,这使得从源代码重建和检查签名变得非常困难。
因此,如果您真的需要这个,您需要一个简单且便携的方法。
坏消息是 C 标准对此没有通用的解决方案。
标准对填充字节和位的内容的唯一保证是针对静态存储的未初始化结构。在这种情况下(在托管环境中),填充保证为零。实际上,初始化结构也是如此,因为编译器编写者这样做很简单。
具有自动存储功能的本地结构呢?如果它们未被初始化,则字段和填充内容都是不确定的。如果你只是用 memset(&s, 0, sizeof(s))
清除字节,填充将被清除,你可以开始修改结构成员......再次是坏消息:C 标准描述为 未指定的行为 在结构或联合中存储值时填充字节的值(6.2.6.1)。
换句话说,在结构成员中存储值会对填充位和字节的内容产生副作用。允许编译器生成执行此操作的代码,这样做可能更有效。
Marek 描述的方法超出了简单 memset
使用起来非常麻烦,尤其是当您有位域时。实际上,在手动初始化字段之前清除结构似乎是实现该目的的最简单方法,而且我还没有看到编译器利用标准对填充字节的宽大处理。如果按值传递结构,则所有赌注都将关闭,因为编译器可能生成不复制填充的代码。
作为一个结论:如果你使用局部结构,在使用前用memset
清除它们并且不要按值传递它们。没有保证填充将保持 0 值,但这是你能做的最好的。