C 为什么这个结构没有正确对齐?

C 为什么这个结构没有正确对齐?,c,gcc,struct,sizeof,memory-alignment,C,Gcc,Struct,Sizeof,Memory Alignment,我在读这个答案:我很好奇为什么: struct ST { long long ll; char ch2; char ch1; short s; int i; }; 仍然是24字节而不是16字节的大小。我希望2*char+short+int可以容纳8个字节。为什么会这样 编辑: 很抱歉造成混淆,我运行的是64位系统(debian)gcc(debian 4.4.5-8)4.4.5。我已经知道这是因为填充。我的问题是为什么?其中一个答案是: char = 1 byte

我在读这个答案:我很好奇为什么:

struct ST
{
   long long ll;
   char ch2;
   char ch1;
   short s;
   int i;
};
仍然是24字节而不是16字节的大小。我希望2*char+short+int可以容纳8个字节。为什么会这样

编辑:

很抱歉造成混淆,我运行的是64位系统(debian)gcc(debian 4.4.5-8)4.4.5。我已经知道这是因为填充。我的问题是为什么?其中一个答案是:

char = 1 byte
char = 1 byte
short = 1 byte (why is this 1 and not 2?)
* padding of 5 bytes

我的问题是,为什么这里有填充物。。。为什么不把int直接放在short后面,它仍然可以放在8个字节内。

通常为了减少填充,通常的做法是将成员从最大到最小排序,你能尝试重新排序,看看结果如何吗

struct ST
{
   long long ll;  //8 bytes
   int i;         //4bytes
   short s;       //2 bytes
   char ch2;      //1 byte
   char ch1;      //1 byte
};

总共是16个字节

都是关于填充的。在VisualStudio(和其他一些编译器)中,可以使用#pragma push/pack使其按照您的意愿对齐

#pragma pack(push, 1)
struct ST
{
   /*0x00*/ long long ll;
   /*0x08*/ char ch2;
   /*0x09*/ char ch1;
   /*0x0a*/ short s;
   /*0x0c*/ int i;
   /*0x10*/
};
#pragma pack(pop)
既然你说它的大小是24,我猜编译器会通过如下操作将你的大小调整为4字节:

struct ST
{
   /*0x00*/ long long ll;
   /*0x08*/ char ch2;
   /*0x09*/ char padding1[0x3];
   /*0x0c*/ char ch1;
   /*0x0d*/ char padding2[0x3];
   /*0x10*/ short s;
   /*0x11*/ char padding3[0x2];
   /*0x14*/ int i;
   /*0x18*/
};

(对不起,我在做这类事情时使用十六进制。0x10是十进制的16,0x18是十进制的24。)

简单的答案是:它不是24字节。或者您正在Linux的64位s390端口上运行,我还没有找到ABI文档。Debian可以在其上运行的每一个64位硬件的结构大小都是16字节

我已经为一堆不同的CPU ABI挖掘了ABI文档,它们或多或少都有这样的措辞(似乎它们都是相互复制的):

结构和联合体假定其最严格对齐的组件对齐。每个杆件都指定给具有适当路线的最低可用偏移。任何对象的大小始终是对象对齐的倍数

我发现的所有体系结构ABI文档(mips64、ppc64、amd64、ia64、sparc64、arm64)都与char 1、short 2、int 4和long long 8对齐

尽管允许操作系统创建自己的ABI,但几乎所有类似unix的系统,尤其是Linux,都遵循system V ABI及其补充CPU文档,这些文档非常详细地说明了这种行为。Debian绝对不会改变这种行为,使其与所有其他Linuxes不同

下面是一个快速验证(全部在您最有可能运行的amd64/x86_64上):

Ubuntu:

$ cc -o foo foo.c && ./foo && uname -ms
16
Linux x86_64
CentOS:

$ cc -o foo foo.c && ./foo && uname -ms
16
Linux x86_64
OpenBSD:

$ cc -o foo foo.c && ./foo && uname -ms
16
OpenBSD amd64

你的汇编还有其他问题。或者这不是您正在测试的结构,或者您正在一个非常奇怪的硬件架构上运行,并将其指定为“64位”相当于说“我驾驶的是这辆政府发行的汽车,它有非常奇怪的加速,发动机在5分钟后熄火”不要提你说的是航天飞机。

你是在64位系统上检查这个吗?还可以检查到构件的偏移,以查看它们最终使用宏的位置。关于你在标题中的措辞,编译器选择的对齐方式对于你的系统来说肯定是“合适的”。因为填充。什么是“64位系统”?硬件架构是什么?在x86_64 ABI上,该结构的大小应为16字节。我在Ubuntu、MacOS、OpenBSD和Centos上进行了验证。它不依赖于编译器,因此您的编译标志有很大的问题,或者您运行的是alpha或类似的东西。我刚刚验证了arm64、powerpc64和sparc64的ABI文档(仍在寻找alpha和ia64的文档)。这些硬件体系结构也应该使结构的大小为16。你能在发生这种情况的机器上发布演示
uname-a
行为和输出的完整程序吗?哪个CPU ABI会指定这种奇怪的对齐和填充?即使是没有访问一个或两个字节值的指令的alpha,也不需要4字节的短路对齐。
$ cc -o foo foo.c && ./foo && uname -ms
16
Linux x86_64
$ cc -o foo foo.c && ./foo && uname -ms
16
OpenBSD amd64