内存对齐

来源:互联网 发布:告白墙源码 编辑:程序博客网 时间:2024/06/06 10:44

讨论

  • 32-bit机器,一次总线访问最多32bit数据
    • 32bit以内的数据,一次总线传输即可完成。
  • 机器的设计:
    • 32-bit机器,访问一个32-bit数据(int)
      • 可以一次取8bit,共取4次,放到总线
      • 一次取16bit, 共取2次,放到总线
      • 一次取32bit, 取1次,放到总线
    • 可见,机器为了实现效率,一定会在电路设计上做到:
      • 地址线多宽,一次就能访问多长的数据,而不用改变电信号。
      • 为了简便,干脆使访问地址都是宽度的整数倍
    • 所以:
      • 在32-bit机器上,访问的地址是4的倍数
      • 在64-bit机器上,访问的地址是8的倍数
      • 如果数据地址不是倍数的话,就需要再做移位运算
    • 在这种存储方式下,时间效率最优
    • 当然,你也可以给机器说,我放弃时间效率最优,因为我的存储空间捉襟见肘。机器说,好吧,那你来指定存放方式。于是就可以手动修改为2字节对齐,4字节对齐。但你不能说3字节对齐,char(1),short(16),int(32), 如果用3字节对齐,时间空间都牺牲了。
    • 所谓以n字节对齐,相当于你把地址线宽度修改成了n,在地址线宽度n的情况下实现时间效率最优。

说明

struct Stru{    char a;    short b;    char c;};

32-bit机器(4字节对齐),上述结构体size为6,如果变为

struct Stru{    char a;    char c;    short b;};

size为4.

看这段代码:

int main(void){    char a;    char b;    short c;    printf("&a : %p\n", &a);    printf("&b : %p\n", &b);    printf("&c : %p\n", &c);    return 0;}

打印:

&a : 0x7fff548fabfb&b : 0x7fff548fabfa&c : 0x7fff548fabf8

在内存中的地址顺序:c, a, b. 这与结构体不一样,结构体中实际顺序是书写顺序,但在这里不是。

调整一下顺序:

char a;short c;char b;

打印:

&a : 0x7fff546cdbfb&b : 0x7fff546cdbf7&c : 0x7fff546cdbf8

顺序: b, c, a

一般变量在存储时,由编译器决定顺序。 编译器会进行优化。

Questions

32-bit机器上,4字节对齐,char+short结构体怎么放?

假如char放在0x0000处,short放在0x0001吗?这样放似乎没有什么问题。

然而,struct可以构成结构体数组,来看看这会出现什么情况

图中斜线表示char, 方格表示padding.

可以看到,第一个short首地址偏移1, 第二个往后变成了2. 也就是说,在结构体数组中,成员变量偏移不确定。所以这种情况是一定要避免的。解决的方法就是(设n字节对齐):当成员变量小于等于n时,成员变量的地址是它宽度的整数倍. 结构体size为最大成员变量的整数倍。 这样,在上述情况中,short就总是偏移2了。

32-bit和64-bit机器上,下面结构体的大小

#include <stdio.h>//#pragma park(4)struct Str{    char a;    long b;    char c;};int main(void){    struct Str st;    printf("size of struct st: %lu\n", sizeof(st));    return 0;}

64-bit: size of struct st: 24

32-bit: size of struct st: 16

我用的64bit机器,所以4字节对齐时,我加上#pragme pack(4)

下面解释一下:

根据上面的结论:当成员变量小于等于n时,成员变量的地址是它宽度的整数倍。结构体size为最大成员变量的整数倍。 当n = 8, 结构体为8×3 = 24.

n = 4, long大于n,成员变量的地址应是4的整数倍,结构体size为4的整数倍。这时4×4 = 16.

0 0
原创粉丝点击