代码之家  ›  专栏  ›  技术社区  ›  nglee

具有两个双精度的结构的对齐方式为4,即使双精度对齐为8(32位)

  •  3
  • nglee  · 技术社区  · 8 年前

    我在一台x86_64机器上,有Ubuntu 16.04和gcc 5.4.0。

    我今天遇到了这种有点奇怪的行为。

    $ cat main.c
    #include <stdio.h>
    struct dd { double d1; double d2; };
    int main()
    {
        printf("%d\n", (int)__alignof__(double));
        printf("%d\n", (int)__alignof__(struct dd));
    }
    $ gcc -m32 -o main main.c && ./main
    8
    4
    

    __alignof__ double struct dd 我觉得这对一个 struct gcc 5.4.0 doc :

    注意,任何给定的 union ISO C标准要求类型至少是所有构件对齐的最低公倍数的完美倍数 协会 有疑问

    这种行为的原因可能是什么?正在调整此 4字节是一种优化的内存访问方式?

    1 回复  |  直到 8 年前
        1
  •  4
  •   Community CDub    5 年前

    指定这在您的架构上应该如何表现的文档是 here, in the i386 System V psABI (当前版本) here 标记wiki)。在这本书中,我们可以看到double的所需对齐是4。但它有一个有趣的注释:

    符合Intel386 ABI。使用双字对齐构建的程序 以及下面的联合和本章后面的函数调用序列

    GCC不希望违反结构的ABI(其中对齐非常相关),因此它正确地将4对齐用于结构内部的双精度对齐。

    __alignof__ 不是任何C标准的一部分。编译器可以做任何事情,比如从互联网上获取一只猫的图片并显示给你,这将是一种完全符合C标准的行为。

    C11没有指定 _Alignof 不过是操作员。有趣的是,如果我们使用 操作员是C11标准的一部分,GCC报告其他(正确)数字:

    $ cat foo.c
    #include <stdio.h>
    struct dd { double d1; double d2; };
    int main()
    {
        printf("%d\n", (int)__alignof__(double));
        printf("%d\n", (int)__alignof__(struct dd));
    }
    $ cc -m32 -o foo foo.c && ./foo
    8
    4
    $ ed foo.c
    [...]
    $ cat foo.c
    #include <stdio.h>
    struct dd { double d1; double d2; };
    int main()
    {
        printf("%d\n", (int)_Alignof(double));
        printf("%d\n", (int)_Alignof(struct dd));
    }
    $ cc -m32 -o foo foo.c && ./foo
    4
    4
    

    C标准的措辞对于ABIs中应该发生的事情不是很具体,其中结构内部的类型的对齐度低于结构外部的类型。

    After careful reading of the standard's wording 和一些争论,gcc开发人员决定 _对齐 应该告诉您在严格的C11程序中该类型值的最小对齐方式( https://gcc.gnu.org/ml/gcc-patches/2013-12/msg00435.html ). (这是您在编写垃圾收集器之类的用例时想要的,垃圾收集器扫描内存块以寻找潜在的指针。)注意,C11不包括 __attribute__((packed)) ,并且投射未对齐的指针是UB。

    This mailing list post ,但不是C++ alignof __对齐__

    GNU C的 __对齐__ double 一直到8B;这是当前编译器在性能方面的纯可选行为。

    _Alignof(double) <= _Align(struct containing_double) 是8B。 双重的 当跨越4B边界时工作,如果它跨越缓存线或页面,则速度很慢。

    _Atomic long long Current gcc is broken 对于32位SysV ABI上的C11 stdatomic 8B类型,有望更改为匹配clang。)


    叮当作响, __对齐__ 因此,它与gcc在C11运算符方面不一致(但与结构布局无关,C11 stdatomic除外)。

    on the Godbolt compiler explorer 使用gcc7.2和clang4.0。卸下 -xc 编译为C++而不是C


    max_align_t 在8到16的32位中, for _Float128 但是 malloc(8) strdup("abc") 可能仍然只返回8B对齐的块。

    gcc's stddef.h implements max_align_t

    long long __max_align_ll __attribute__((__aligned__(__alignof__(long long))));
    

    确保生成的结构确实具有同样大的对齐需求( _Alignas long double __float128 成员。