【问题标题】:Why is a double member in struct not aligned on 8 byte boundary?为什么结构中的双重成员未在 8 字节边界上对齐?
【发布时间】:2013-01-31 08:59:58
【问题描述】:

这是关于内存对齐的。在下面的代码中,我预计结构内 b 的偏移量为 8(32 位机器)。见here。因此,使b 始终出现在缓存行中。然而,事实并非如此。 struct test1 的全局对象中的成员 b 似乎是对齐的。我不确定它是偶然还是编译器故意这样做。

我想了解为什么编译器没有在 a 之后填充 4 个字节。

struct test1
{
int a;
double b;
}t1;

int main()
{
struct test1 *p = malloc(sizeof(struct test1));
printf("sizes int %d, float %d, double %d, long double %d\n", sizeof(int), sizeof(float), sizeof(double), sizeof(long double));
printf("offset of b %d\n",(int)&(t1.b)-(int)&(t1));

printf("\naddress of b (on heap) = %p, addr of b (on data seg) = %p\n",&(p->b), &(t1.b));

return 0;
}

输出是……

sizes int 4, float 4, double 8, long double 12
offset of b 4

address of b (on heap) = 0x804a07c, addr of b (on data seg) = 0x80497e0

我在 ubuntu 10.04 上使用标准 gcc 编译器

【问题讨论】:

  • 一方面,如果 CPU 可以处理未对齐的操作数,那就没有问题。现在,为什么您的编译器要紧密打包结构,这是一个问题。你是如何编译代码的?是否有来自 makefile 或编译器可能从其配置文件中提取的任何隐藏编译选项?
  • @Alexey,不,它只是 gcc test.c; ./a.out
  • 在使用“默认”选项和 -m32 使用 gcc 4.6.3 进行编译时,我得到了相同的结果(我有一个 64 位操作系统,所以默认是 64 位,在这种情况下,它给了我一个 8 字节对齐)。
  • gcc 将 Linux x86 上的双精度对齐到 4 个字节。如果您想要 8 字节对齐,请使用 -malign-double。您链接到错误事实的问题,因为对齐是一个依赖于平台的问题,甚至 Windows 和 linux 平台在 x86 上对齐双重不同
  • 这是 Unix i386 ABI。 double 需要在 4 字节边界上对齐。其他 ABI(和其他架构)可能有其他要求。

标签: c alignment


【解决方案1】:

根据System V ABI for i386,第 28 页,double 仅获得 4 字节对齐,但建议编译器也提供 8 字节选项。看来这是 GCC 在 Linux 上实现的,该选项被称为 -malign-double

另一种方法是使用-m64 来获取 x86-64 目标代码,这已经是包括 Mac OS X 在内的某些系统的默认设置。

【讨论】:

    【解决方案2】:

    我预计结构中 b 的偏移量为 8(32 位机器)。看这里

    您的参考资料解释了为什么 8 对齐双打可能是有利的。这并不等于 保证双打总是 8 对齐的。如果您的消息来源说它们始终是 8 对齐的,而您观察到它们并非如此的实现,那么您的来源是错误的。

    来自 GCC 手册页:

    对齐 两个字边界上的“双”变量将产生代码 在 Pentium 上运行得更快一些,但会消耗更多内存。

    所以 GCC 声明 4 对齐的原因是为了节省内存。您可以使用-malign-double-mno-align-double 来控制它,当然,如果您在使用冲突选项编译的代码之间共享结构,您当然会冒着创建二进制不兼容的风险。对于特定的对象/结构成员,您可以使用 GCC 自己的 __attribute__((aligned))_Alignas(在 C11 中)或 alignas(在 C++11 中),所有这些都可以采用整数常量来指定所需的对齐方式。

    【讨论】:

      【解决方案3】:

      在 ANSI C 中根本无法保证对齐。

      自动变量的对齐比堆上声明的任何内容都多。如果您使用的是 POSIX 操作系统,请使用 memalign(3) 接收您确定已对齐的内存。 Malloc 可以在任何偏移量处返回内存。您可以使用像 __attribute__ ((__packed__)) 这样的编译器指令来添加您自己的对齐方式。

      【讨论】:

        猜你喜欢
        • 2011-01-23
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-03-25
        • 2012-07-18
        • 2017-07-28
        • 1970-01-01
        • 2012-04-30
        相关资源
        最近更新 更多