编译器会偷偷增加结构的对齐吗?

wangt0907

我有一个 8 字节对齐的结构,但是当我连续定义一些这种类型的变量而不是在数组中时,它似乎是 16 字节对齐。我的问题是,编译器是否出于某种目的增加了对齐?

我的测试代码是:

#include <stdio.h>
#include <stdint.h>
struct a{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;

int main(){
    printf("%lx\n", (uintptr_t)&a1);
    printf("%lx\n", (uintptr_t)&a2);
    printf("%lx\n", (uintptr_t)&a3);
    return 0;
}

输出是:

601030
601050
601070
乔纳森·莱夫勒

在 64 位 Unix 机器(运行 macOS Sierra 10.12.6,使用 GCC 7.1.0 的 Mac)上,此代码:

#include <stdio.h>
#include <inttypes.h>
struct a
{
    long l[3];
};

struct a a1;
struct a a2;
struct a a3;
struct a a4[4];

int main(void)
{
    printf("sizeof(struct a) = %zu\n", sizeof(struct a));
    printf("a1 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a1);
    printf("a2 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a2);
    printf("a3 = 0x%.16" PRIXPTR "\n", (uintptr_t)(void *)&a3);
    for (int i = 0; i < 4; i++)
        printf("a4[%d] = 0x%.16" PRIXPTR "\n", i, (uintptr_t)(void *)&a4[i]);
    return 0;
}

产生这个结果:

sizeof(struct a) = 24
a1 = 0x0000000106776020
a2 = 0x0000000106776040
a3 = 0x0000000106776060
a4[0] = 0x0000000106776080
a4[1] = 0x0000000106776098
a4[2] = 0x00000001067760B0
a4[3] = 0x00000001067760C8

请注意,这三个独立结构布局在 32 字节边界上,但数组中的结构布局在 24 字节边界上,这在考虑到结构大小(24 字节)的情况下是可以预料的。

相比之下(与此答案的早期版本相反),使用 Clang ( Apple LLVM version 8.1.0 (clang-802.0.42))编译会产生结果:

sizeof(struct a) = 24
a1 = 0x0000000102ACE020
a2 = 0x0000000102ACE038
a3 = 0x0000000102ACE050
a4[0] = 0x0000000102ACE070
a4[1] = 0x0000000102ACE088
a4[2] = 0x0000000102ACE0A0
a4[3] = 0x0000000102ACE0B8

请注意,单个结构现在布置在 24 字节边界上(或者,至少相隔 24 字节,而不是 GCC 中的 32 字节)。

我没有解释为什么 GCC 添加空间,但编译器完全可以自由地这样做。两个编译器都是正确的——结果完全不同。

本文收集自互联网,转载请注明来源。

如有侵权,请联系[email protected] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

Java编译器会汇编吗?

来自分类Dev

编译器会优化返回固定大小数组的结构的函数吗?

来自分类Dev

编译器会优化返回固定大小数组的结构的函数吗?

来自分类Dev

Java编译器警告会影响编译时间吗?

来自分类Dev

Java编译器警告会影响编译时间吗?

来自分类Dev

C#编译器会优化此代码吗?

来自分类Dev

编译器会自动创建返回变量吗?

来自分类Dev

C编译器会重复删除(合并)代码吗?

来自分类Dev

编译器会优化未使用的链接文件吗?

来自分类Dev

编译器会优化集合初始化吗?

来自分类Dev

编译器会丢弃空方法吗?

来自分类Dev

显式算术,编译器会处理吗?

来自分类Dev

编译器会优化除法乘法吗

来自分类Dev

编译器会删除无效的引用吗?

来自分类Dev

显式算术,编译器会处理吗?

来自分类Dev

结构与不同编译器上的显式宽度成员对齐

来自分类Dev

是否可以在编译器对齐之前获取类/结构的原始大小?

来自分类Dev

为什么编译器要向已经 4 字节对齐的结构添加填充?

来自分类Dev

C编译器自动版本增加

来自分类Dev

GNU GCC 编译器 - 对齐属性

来自分类Dev

在C#中,内部结构会向编译器发出警告

来自分类Dev

在C#中,内部结构会向编译器发出警告

来自分类Dev

从内存缓冲区读取结构会引发编译器错误和段错误

来自分类Dev

为什么编译器将此变量初始化为错误的值?这是对齐问题吗?

来自分类Dev

大量警告会增加编译时间吗?

来自分类Dev

编译器对结构进行重新排序

来自分类Dev

我可以让编译器优化结构中的函数调用吗?

来自分类Dev

我实现is_complete类型特征会暴露出编译器错误吗?

来自分类Dev

这可能会永久且意外地覆盖编译器自身的功能吗?

Related 相关文章

  1. 1

    Java编译器会汇编吗?

  2. 2

    编译器会优化返回固定大小数组的结构的函数吗?

  3. 3

    编译器会优化返回固定大小数组的结构的函数吗?

  4. 4

    Java编译器警告会影响编译时间吗?

  5. 5

    Java编译器警告会影响编译时间吗?

  6. 6

    C#编译器会优化此代码吗?

  7. 7

    编译器会自动创建返回变量吗?

  8. 8

    C编译器会重复删除(合并)代码吗?

  9. 9

    编译器会优化未使用的链接文件吗?

  10. 10

    编译器会优化集合初始化吗?

  11. 11

    编译器会丢弃空方法吗?

  12. 12

    显式算术,编译器会处理吗?

  13. 13

    编译器会优化除法乘法吗

  14. 14

    编译器会删除无效的引用吗?

  15. 15

    显式算术,编译器会处理吗?

  16. 16

    结构与不同编译器上的显式宽度成员对齐

  17. 17

    是否可以在编译器对齐之前获取类/结构的原始大小?

  18. 18

    为什么编译器要向已经 4 字节对齐的结构添加填充?

  19. 19

    C编译器自动版本增加

  20. 20

    GNU GCC 编译器 - 对齐属性

  21. 21

    在C#中,内部结构会向编译器发出警告

  22. 22

    在C#中,内部结构会向编译器发出警告

  23. 23

    从内存缓冲区读取结构会引发编译器错误和段错误

  24. 24

    为什么编译器将此变量初始化为错误的值?这是对齐问题吗?

  25. 25

    大量警告会增加编译时间吗?

  26. 26

    编译器对结构进行重新排序

  27. 27

    我可以让编译器优化结构中的函数调用吗?

  28. 28

    我实现is_complete类型特征会暴露出编译器错误吗?

  29. 29

    这可能会永久且意外地覆盖编译器自身的功能吗?

热门标签

归档