杂谈c语言——3.内存对齐

码码生的 2024-08-14 15:05:03 阅读 99

先看两个例子:

<code>typedef struct S {

int a;

double b;

char c;

}S;

typedef struct B {

int a;

char b;

double c;

}B;

int main() {

printf("S : %d\n", sizeof(S));

printf("B : %d\n", sizeof(B));

return 0;

}

结果为:

S:24;

B:16: 

可见不同,简单来说就是按照成员的定义顺序,依次为其分配内存,分配内存的起始偏移位置应该是选定对齐数的整数倍,最后结构体变量所占大小应该是成员最大对齐数的整数倍。 

1.对齐原则 

 内存对⻬规则

• 第⼀个成员在与结构体偏移量为0的地址处。

• 其他成员变量要对⻬到某个数字(对⻬数)的整数倍的地址处

• 注意:对⻬数 = 编译器默认的⼀个对⻬数 与 该成员⼤⼩的较⼩值。

• VS中默认的对⻬数为8

• 结构体总⼤⼩为:最⼤对⻬数(所有变量类型最⼤者与默认对⻬参数取最⼩)的整数倍

• 如果嵌套了结构体的情况,嵌套的结构体对⻬到⾃⼰的最⼤对⻬数的整数倍处,结构体的整体⼤⼩ 就是所有最⼤对⻬数(含嵌套结构体的对⻬数)的整数倍。

 

举例证明

//练习1.

struct A {

char c;

int i;

char b;

};

int main(){

printf("%d\n",sizeof(struct A));

return 0;

}

   结构体成员变量分配内存的详细过程:

        1.首先:char c为第一个成员变量,遵循第一条规则,char c从偏移量0开始,占1个字节,指针指向下一个偏移地址1

        2.接下来存放int i, 但偏移地址 “1” 并不是对齐数4的整数倍

对齐数4来自(对齐数 = 编译器默认的一个对齐数 与 该成员大小的较小值。)规则2,成员变量2是int类型,大小为4字节,在VS中,编译器默认对齐数为8,8与4的较小值为4,所以成员变量2的对齐数为4

那么指针需要移动到对齐数4的整数倍,即偏移量4地址处,开始存放int i 占4个字节,且偏移量1~3为空闲区,浪费了。

        3.接下来指针指向了偏移地址9,第三个成员变量char b的对齐数是1,偏移9是对齐数1的整数倍,符合条件,存放char b,占一字节,指针指向偏移10地址,由第三条规则可知,. 结构体总大小为最大对齐数(每个成员变量都有一个对齐数)的整数倍,struct A最大对齐数是int i的对齐数4,那么现偏移10并不是对齐数4的整数倍,指针继续向下寻找符合条件的偏移地址,最后指针指向偏移12,12是4的整数倍,符合规则,那么偏移结束。

        结果共占12字节,内存中浪费了6个字节。

                           

 

 

 

2.强化训练

<code>struct S3

{

double d;

char c;

int i;

};

struct S4

{

char c1;

struct S3 s3;

double d;

};

int main(){

printf("%d\n", sizeof(struct S4));

return 0;

}

由对齐原则可知sizeof(s3)=16;

计算sizeof(s4)

 练习4.结构体内存分配过程:

   1.首先:char c1为第一个成员变量,遵循第一条规则,char c从偏移量0开始,占1个字节,指针指向下一个偏移地址1

   2.其次,第二个成员变量为结构体S3,说明是嵌套结构体,通过刚才对S3的结构体大小可知是16字节,且S3中最大对齐数为8,通过规则4可知,现指针指向的偏移地址1并不是对齐数8的整数倍,所以指针需要向后跳转,直到指针指向偏移量为8的地址,才符合要求,开始存放struct S3成员变量,共16字节

    3.最后,指针指向偏移量为24的地址处,最后一个成员变量为double d,d的对齐数为8,偏移地址“24”是对齐数8的整数倍,所以开始存放double d,占8字节。

        现在指针指向了偏移量为32的地址,32是整个结构体最大对齐数8的整数倍,偏移结束,结构体S4共占32字节,浪费了7个字节(偏移地址1~7)。

 

 

3.内存对齐的原因 

 1. 不是所有的硬件平台都支持随意地址访问,有些硬件平台cpu只能从指定地址处读取指定大小的数据,减少了异常抛出。

 

 

!!!!!!!!!!!

第一个因为内存对齐,虽然ch只有1字节,但浪费3个字节 可以保证只读取到ch (不读到i)

第二个因为内存不对齐,会访问到ch和i的前3个字节的内容。会出问题



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。