V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
csfreshman
V2EX  ›  程序员

求教大佬们一个内存对齐的问题(c++ centos7 64 位系统)

  •  
  •   csfreshman · 2021-05-09 22:15:31 +08:00 · 1722 次点击
    这是一个创建于 1076 天前的主题,其中的信息可能已经有所发展或是发生改变。
    /*
    说明:程序是在 centos7 64 位系统下测试的
    */
    #include <iostream>
    
    using namespace std;
    
    struct A
    {
        short var; 
        int var1;  
        long var2; 
        char var3; 
        string s;  
    };
    
    int main()
    {
        short var;
        int var1;
        long var2;
        char var3;
        string s;
        A ex1;
        cout << sizeof(var) << endl;  // 2 short
        cout << sizeof(var1) << endl; // 4 int
        cout << sizeof(var2) << endl; // 8 long
        cout << sizeof(var3) << endl; // 1 char
        cout << sizeof(s) << endl;    // 8 string
        cout << sizeof(ex1) << endl;  // 32 struct
        return 0;
    }
    

    输出结果:

    [root workspace]#./align
    2
    4
    8
    1
    8
    32
    

    这里对齐怎么搞成了占用 32 个字节呢? 按照 8 字节对齐的话,5*8 = 40 字节 难道第一个 short 和 var1 共同占用 8 个字节? ( short 后面填充两个字节)

    12 条回复    2021-05-10 16:25:27 +08:00
    csfreshman
        1
    csfreshman  
    OP
       2021-05-09 22:23:42 +08:00
    自己顶一下,大佬们都休息了吗
    YePiaoling
        2
    YePiaoling  
       2021-05-09 22:34:20 +08:00
    是的,可以搜索一下“C++ 内存对齐”
    drizztdu
        3
    drizztdu  
       2021-05-09 22:36:17 +08:00 via iPhone
    第一个 short 和 var1 共同占用 8 个字节。把 struct A 的 var2 放到第一位,对其后就占用 24 个字节了。
    @csfreshman
    billlee
        4
    billlee  
       2021-05-09 22:38:11 +08:00
    内存对齐基本上可以概括成一个字段的起始地址能被 min {字段大小, 体系字长} 整除
    csfreshman
        5
    csfreshman  
    OP
       2021-05-09 22:43:57 +08:00
    @drizztdu 啥意思?把 var2 放第一行有啥区别?还是占 32 个字节吧,我跑了下还是 32 个字节。
    jim9606
        6
    jim9606  
       2021-05-09 22:44:52 +08:00
    var1:0-2
    var2:4-8
    var3:8-16
    var4:16-17
    var5:24-32
    起始偏移要是成员大小的整数倍。
    irytu
        7
    irytu  
       2021-05-09 23:00:12 +08:00 via iPhone
    一般结构体里面 考虑对齐的话建议由大到小的顺序摆放 你可以画个图来推演一下 ,对于 struct A 的话( 64bit ):

    最小空间:8, 8, 4, 2, 1 = 24 bytes,4 、2 、1 在一个字节里
    irytu
        8
    irytu  
       2021-05-09 23:00:31 +08:00 via iPhone
    说错了 4 、2 、1 在一个 8 字节里
    hei1000
        9
    hei1000  
       2021-05-09 23:14:44 +08:00
    我的结果是
    ```
    2
    4
    8
    1
    32
    56
    ```

    Manjro-Linux 64-bit, g++ (GCC) 10.2.0
    learningman
        10
    learningman  
       2021-05-10 01:27:33 +08:00
    2
    4
    4
    1
    24
    40
    VS
    geebos
        11
    geebos  
       2021-05-10 11:17:50 +08:00
    每个类型都有一个对齐值,一般是类型所占内存大小。结构体也有个对齐值,就是结构体成员的对齐值的最大值。

    在进行内存对齐的时候要满足以下要求:
    - 结构体长度要能够整除结构体的对齐值
    - 结构体中成员地址到结构体首地址的偏移量要能够整除该成员的对齐值

    回到这个问题上来:
    - short 的长度是 2 字节,所以对齐值也是 2 字节,偏移量为 0,所以不用处理
    - int 的长度是 4 字节,但是偏移量是 2 字节(前面成员的所占长度),所以要将偏移量补到( 2+2 ) 4 字节
    - long 的长度是 8 字节,偏移量是( 2+2+4 ) 8 字节,可以整除 8,,满足条件
    - char 的长度是 1 字节,偏移量是( 2+2+4+8 ) 16 字节,满足条件
    - string 的长度是 8 字节,偏移量是( 2+2+4+8+1 ) 17 字节,不满足条件,所以将偏移量补到( 17+7 ) 24 字节

    最后总的长度是( 2+2+4+8+1+7+8 ) 32 字节,并且这个长度能够除以结构体的对齐值( 8 ),所以对齐之后的长度就是 32 字节。
    byaiu
        12
    byaiu  
       2021-05-10 16:25:27 +08:00
    #pragma pack(push,1)
    struct A
    {
    short var;
    int var1;
    long var2;
    char var3;
    string s;
    };
    #pragma pack(pop)
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1127 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 36ms · UTC 23:36 · PVG 07:36 · LAX 16:36 · JFK 19:36
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.