C - 强制与_Alignas说明符对齐 - 为什么内存填充?

时间:2018-05-09 08:11:09

标签: c memory alignment padding

我有一些关于C语言内存对齐的问题,以及在使用_Alignas说明符强制变量与一定数量的字节对齐后如何分配内存。

此代码在输出中显示每个声明变量的内存地址:

#include <stdio.h>

int main(void)
{
       unsigned char dx = 1;
       unsigned char ca  = 1;
       unsigned char cx  = 1;
       unsigned char dz = 1;
       unsigned char cb = 1;
       unsigned char _Alignas(double)  cz = 1;

       char * p_begin = (char *) &cz;
       char * p_end = (char * ) &dx + sizeof(dx);

       printf("Addresses   Value\n");
       for (char * p = p_begin; p < p_end; p++)
       {
              printf("%9p   %6X", p, 0xff & *p);

              if (p == (char *) & dx) printf(" <- dx\n");
              else if (p == (char *) & ca) printf(" <- ca\n");
              else if (p == (char *) & cx) printf(" <- cx\n");
              else if (p == (char *) & dz) printf(" <- dz\n");
              else if (p == (char *) & cb) printf(" <- cb\n");
              else if (p == (char *) & cz) printf(" <- cz\n");
              else printf("\n");
       }

       return 0;
}

在我的电脑上,输出如下:

Addresses   Value
   28ff08        1 <- cz
   28ff09       FF
   28ff0a       28
   28ff0b        0
   28ff0c       CE
   28ff0d       2A
   28ff0e       40
   28ff0f        1 <- cb
   28ff10        1 <- dz
   28ff11        1 <- cx
   28ff12        1 <- ca
   28ff13        1 <- dx

Process returned 0 (0x0)   execution time : 0.016 s
Press any key to continue.

在8字节强制cz变量对齐后,我希望看到的唯一行为是cz被分配给一个值为8的倍数的地址,我不希望这样做请参阅填充中的cz。怎么来这个行为? 另外我预计对应于填充的字节数与1字节的数据大小相结合会产生8,而填充占用6个字节的原因是什么?

1 个答案:

答案 0 :(得分:0)

堆栈通常会向下增长。没有必要的理由;它主要是历史发展的结果。为堆栈分配一个内存区域,堆栈指针设置为指向它的高端,并启动程序的主程序。由于程序需要更多的堆栈空间,因此会减少堆栈指针。

您的示例中似乎发生的是编译器按照遇到的顺序为对象分配空间。首先会看到dx,因此会为堆栈0x28ff13分配下一个可用空间。然后会看到ca,并为其分配0x28ff12。我们看到,随着堆栈的增长,它从更高的地址(它开始的地方)开始到更低的地址。

当编译器到达cz时,您已请求八字节对齐,编译器跳转到下一个八的倍数(仍在向下方向),即0x28ff08。< / p>

当然编译器可以查看整个情况(而不是一次查看每个对象)并将cz放在0x28ff10并将其他对象放在它周围,使用更少的堆栈空间。如果在启用优化的情况下进行编译,编译器可能会这样做。另一方面,编译器可能要求您的平台将堆栈指针保持对齐八个字节(或更多),因此重新排列这些特定对象无论如何都不会保存任何堆栈空间。

C标准中没有关于此的规则。编译器可以自由选择它的堆栈。