如何告诉 gcc 禁用结构内的填充?
How to tell gcc to disable padding inside 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
[=33之间有2个字节的差距=] 设置为 0x0。这意味着 i
正在对齐。
当我打印那部分结构时,这是非常清楚的,因为 with :
for(int i=28;i<35;i++)
printf("%02hhX",buf[i]);
我在屏幕上显示 EBF40000EB90EB90
。
我在我的程序中尝试了volatile struct list data;
之类的东西,但它并没有改变对齐问题。
那么是否有 #pragma
或 __attribute__
告诉 gcc 在 struct list
type 中不对齐 i
?
在 GCC 中,您可以像这样使用 __attribute__((packed))
:
// sizeof(x) == 8
struct x
{
char x;
int a;
};
// sizeof(y) == 5
struct y
{
char x;
int a;
} __attribute__((packed));
见doc。
此外,如果您依赖结构字段的地址,请查看 offsetof
宏。也许你根本不需要打包结构。
struct
中的字段以实现定义的方式填充。
话虽这么说,字段通常按偏移量对齐,偏移量是相关数据成员(如果成员是数组,则为数组元素)大小的倍数。因此,16 位字段从 2 字节偏移量开始,32 位字段从 4 字节偏移量开始,依此类推。
如果您对 struct
中的字段重新排序以遵守此准则,通常可以避免在 struct
中使用任何内部填充(尽管您最终可能会有一些尾随填充)。
通过将字段置于适当的偏移量,可以比强制打包 struct
.
提高性能
有关详细信息,请参阅 this article on structure packing。
虽然不能保证使用上述技术,但它们往往在大多数情况下都有效。
如@Banex 所述
#pragma pack(push,1)
struct
{
char a;
int b;
long long c;
} foo;
#pragma pack(pop)
#pragma pack(push,1)
内推当前的packing模式,packing设置为1,无padding
#pragma pack(pop)
恢复之前的打包
据称与 Microsoft 的语法兼容
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
我不确定这是正常现象还是编译器错误,但我有一个包含很多成员的 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
[=33之间有2个字节的差距=] 设置为 0x0。这意味着 i
正在对齐。
当我打印那部分结构时,这是非常清楚的,因为 with :
for(int i=28;i<35;i++)
printf("%02hhX",buf[i]);
我在屏幕上显示 EBF40000EB90EB90
。
我在我的程序中尝试了volatile struct list data;
之类的东西,但它并没有改变对齐问题。
那么是否有 #pragma
或 __attribute__
告诉 gcc 在 struct list
type 中不对齐 i
?
在 GCC 中,您可以像这样使用 __attribute__((packed))
:
// sizeof(x) == 8
struct x
{
char x;
int a;
};
// sizeof(y) == 5
struct y
{
char x;
int a;
} __attribute__((packed));
见doc。
此外,如果您依赖结构字段的地址,请查看 offsetof
宏。也许你根本不需要打包结构。
struct
中的字段以实现定义的方式填充。
话虽这么说,字段通常按偏移量对齐,偏移量是相关数据成员(如果成员是数组,则为数组元素)大小的倍数。因此,16 位字段从 2 字节偏移量开始,32 位字段从 4 字节偏移量开始,依此类推。
如果您对 struct
中的字段重新排序以遵守此准则,通常可以避免在 struct
中使用任何内部填充(尽管您最终可能会有一些尾随填充)。
通过将字段置于适当的偏移量,可以比强制打包 struct
.
有关详细信息,请参阅 this article on structure packing。
虽然不能保证使用上述技术,但它们往往在大多数情况下都有效。
如@Banex 所述
#pragma pack(push,1)
struct
{
char a;
int b;
long long c;
} foo;
#pragma pack(pop)
#pragma pack(push,1)
内推当前的packing模式,packing设置为1,无padding
#pragma pack(pop)
恢复之前的打包
据称与 Microsoft 的语法兼容
http://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html