除了使用杂注包或位字段外,我们如何避免C中的结构填充?还有其他方法吗?
7eumitmz1#
把最大的物品放在结构的开始。最后把小的东西打包。
struct optimal_packing { double d; int i[4]; short j[3]; char s[24]; };
字符串更准确地说,具有最严格的对齐要求的项需要最早出现(往往是指针和double或long double),而那些具有较不严格的对齐要求的项则在最后出现(short和char)。如果组件的总长度加起来达到35个字节,但其中一个类型需要8字节对齐,则仍然可以使用尾部填充;会有5个字节的填充。
double
long double
short
char
b0zn9rqh2#
避免结构填充的唯一完全可移植且可靠的方法是根本不在struct中使用真实的成员。使用单个char数组成员,并定义访问其内容的宏:
struct
struct paddingless { // char *p; // double d; // char c; #define OFFSET_P 0 #define OFFSET_D (OFFSET_P + sizeof(char *)) #define OFFSET_C (OFFSET_D + sizeof(double)) #define OFFSET_END (OFFSET_C + sizeof(char)) char data[OFFSET_END]; };
字符串可移植的getter和setter看起来像这样:
inline double paddingless_get_d(const struct paddingless *o) { double val; memcpy(&val, o->data + OFFSET_D, sizeof(val)); return val; } inline void paddingless_set_d(struct paddingless *o, double val) { memcpy(o->data + OFFSET_D, &val, sizeof(val)); }
型如果你知道你的体系结构接受非对齐访问,你可以用一个类型转换来定义一个setter:
#define paddingless_get_d(o) (*(double *) ((o)->data + OFFSET_D)) #define paddingless_set_d(o, val) (*(double *) ((o)->data + OFFSET_D) = (val))
型这是不可移植的,但可能比替代方案更快。它可以在vax x86上工作...
zzwlnbp83#
有些事情需要考虑。首先,编译器添加填充是有原因的:它试图为其指定的平台制作最佳的工作机器代码。所以,正常情况下,填充是一件好事。除了您想要定义数据通信协议、硬件寄存器Map和类似的情况之外,在这些情况下,字节数必须与特定规范相匹配。实际上没有标准的方法来避免填充。最好的方法是在编译时Assert,如果结构的大小与其所有成员的大小之和不匹配,则给出一个错误。当Assert失败时,您可以将编译器设置更改为块填充。优选地:第一个月如果static_assert在你的C编译器中不可用(你需要一个兼容C11的编译器),那么使用一些“ct_assert”宏,你可以在这个网站上找到很多。但是,这并不能以可移植的方式解决问题,您将依赖于编译器设置。解决这个问题的唯一真正可移植的方法是这样的:
void mystruct_copy_from (uint8_t* raw_data, const mystruct_t* ms) { memcpy(raw_data, &ms->x, sizeof(ms->x)); raw_data += sizeof(ms->x); memcpy(raw_data, &ms->y, sizeof(ms->y)); raw_data += sizeof(ms->y); // ... and so on } uint8_t protocol [EXPECTED_STRUCT_SIZE]; mystruct_copy_from (protocol, &mystruct); send(protocol); // some data communication interface without padding
字符串
3条答案
按热度按时间7eumitmz1#
把最大的物品放在结构的开始。最后把小的东西打包。
字符串
更准确地说,具有最严格的对齐要求的项需要最早出现(往往是指针和
double
或long double
),而那些具有较不严格的对齐要求的项则在最后出现(short
和char
)。如果组件的总长度加起来达到35个字节,但其中一个类型需要8字节对齐,则仍然可以使用尾部填充;会有5个字节的填充。b0zn9rqh2#
避免结构填充的唯一完全可移植且可靠的方法是根本不在
struct
中使用真实的成员。使用单个char
数组成员,并定义访问其内容的宏:字符串
可移植的getter和setter看起来像这样:
型
如果你知道你的体系结构接受非对齐访问,你可以用一个类型转换来定义一个setter:
型
这是不可移植的,但可能比替代方案更快。它可以在vax x86上工作...
zzwlnbp83#
有些事情需要考虑。首先,编译器添加填充是有原因的:它试图为其指定的平台制作最佳的工作机器代码。所以,正常情况下,填充是一件好事。除了您想要定义数据通信协议、硬件寄存器Map和类似的情况之外,在这些情况下,字节数必须与特定规范相匹配。
实际上没有标准的方法来避免填充。最好的方法是在编译时Assert,如果结构的大小与其所有成员的大小之和不匹配,则给出一个错误。当Assert失败时,您可以将编译器设置更改为块填充。优选地:
第一个月
如果static_assert在你的C编译器中不可用(你需要一个兼容C11的编译器),那么使用一些“ct_assert”宏,你可以在这个网站上找到很多。
但是,这并不能以可移植的方式解决问题,您将依赖于编译器设置。解决这个问题的唯一真正可移植的方法是这样的:
字符串