如何告诉gcc在struct中禁用填充?
我不确定它是否正常或者它是编译器错误但是我有一个包含很多成员的C结构。 其中包括:
struct list { ... ... const unsigned char nop=0x90; // 27 bytes since the begining of the structure const unsigned char jump=0xeb; // 28 bytes since the begining of the structure const unsigned char hlt=0xf4; // 29 bytes since the begining of the structure unsigned __int128 i=0xeb90eb90eb90eb90f4f4 // should start at the 30th byte, but get aligned on a 16 byte boundary and starts on the 32th byte instead const unsigned char data=0x66; // should start at the 46th byte, but start on the 48th instead. }; // end of struct list.
我很难找到我的程序无法正常工作的原因,但我终于发现hlt
和i
之间有2个字节的间隔设置为0x0。 这意味着i
正在调整。
当我打印那部分结构时,这是非常清楚的,因为:
for(int i=28;i<35;i++) printf("%02hhX",buf[i]);
我在屏幕上看到了EBF40000EB90EB90
。
我试过像volatile struct list data;
这样的东西volatile struct list data;
在我的程序中,但它没有改变对齐问题。
那么是否有一个#pragma
或__attribute__
来告诉gcc不在struct list
type中对齐?
在GCC中,你可以像这样使用__attribute__((packed))
:
// sizeof(x) == 8 struct x { char x; int a; }; // sizeof(y) == 5 struct y { char x; int a; } __attribute__((packed));
见文档 。
此外,如果您依赖struct结构字段的地址,请查看offsetof
宏。 也许你根本不需要打包结构。
正如@Banex所感动的那样
#pragma pack(push,1) struct { char a; int b; long long c; } foo; #pragma pack(pop)
#pragma pack(push,1)
在内部推送当前打包模式,并将打包设置为1,无填充
#pragma pack(pop)
恢复先前的打包
据称与微软的语法兼容
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
struct
中的字段以实现定义的方式填充。
话虽这么说,字段通常是在一个offest上对齐的,这个数字是数据成员(或者如果成员是数组的数组元素)的大小的倍数。 因此,16位字段从2字节偏移开始,32位字段从4字节偏移开始,依此类推。
如果对struct
的字段重新排序以符合此指南,通常可以避免在struct
使用任何内部填充(尽管最终可能会出现一些尾随填充)。
通过将字段放在适当的偏移处,可以在强制打包struct
获得性能提升。
有关更多详细信息,请参阅有关结构打包的文章 。
虽然不能保证使用上述技术,但它们往往适用于大多数情况。