c语言的对齐方式,C语言中内存对齐方式

内存对齐是计算机科学中关于数据结构存储的一种策略,它涉及到不同硬件平台的限制和性能优化。本文详细解释了为何需要内存对齐,以及如何计算内存对齐。在32位系统中,内存对齐规则确保数据在存储时按照特定边界对齐,避免额外的内存访问,提高效率。举例说明了在不同排列顺序下结构体占用内存的计算方法,并指出在跨平台编程中保持内存对齐的一致性至关重要。

内存对齐,因为它是对C/C++程序员透明的,在很多C,C++课本中也没有讲清楚,所以今天写了这篇博客,讲述为什么需要内存对齐,内存对齐怎么计算?

37f6efdfb675d1c8d752b3cba5e228e5.png

为什么需要内存对齐?

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的。某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。

2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

内存对齐怎么计算?

首先,需要知道内存对齐的四个准则:

1.第一个成员与结构体变量的偏移量为0

2.其他变量要对齐到对齐数(对齐数取编译器预设的一个对齐整数与该成员大小的较小值)的整数倍地址

3.结构体总大小为最大对齐数的整数倍

接下来通过几个例子来说明问题:(在4字节的32位机上)

#include

#include

using namespace std;

struct Test

{

int a;

char b;

short c;

};

int main(void)

{

Test test;

printf("a=%p\n", &test.a);

printf("b=%p\n", &test.b);

printf("c=%p\n", &test.c);

cout << sizeof(Test) << endl;

return 0;

}

输出结果:

4c00719e5bdb904cfec853b99c68a329.png

分析过程:

1、首先确定每个成员的有效对齐值,由于这里没有指定对齐值 所以 每个成员的有效对齐值就是其自身数据类型的对齐值

a 的对齐值是 4字节(32位机上) b 的对齐值是 1字节 c 的对齐值是2字节

2、起始地址必须满足“起始地址%N = 0”

令起始地址位0x0000  按照变量的顺序存储 则 0x0000%4 = 0;满足条件 占用4个字节 0x0000-0x0003 折四个字节

变量b 的起始地址 是 0x0004%1 = 0满足条件 占用一个字节 就是0x0004

变量c 的起始地址 是 0x0005%2 !=0 所以起始地址要向后移位 知道满足条件位置 0x0006%2 = 0 满足条件 占用2字节 0x0006- 0x0007

总共占用了8字节

如果变换为这样:

#include

#include

using namespace std;

struct Test

{

char b;

int a;

short c;

};

int main(void)

{

Test test;

printf("a=%p\n", &test.a);

printf("b=%p\n", &test.b);

printf("c=%p\n", &test.c);

cout << sizeof(Test) << endl;

return 0;

}输出:

分析过程:

1、找变量的有效对齐位

还是没有指定对齐值 所以就是变量自身的对齐值 b 1字节, a 4字节,c 2字节

2、起始地址满足 对有效对齐值取余=0的条件

令其实地址为0x0000 % 1 = 0满足

变量a 的起始地址为0x0001 %4 !=0

则其实地址要向后移位 知道满足条件为止 0x0004%4 = 0 占用4个字节 0x0004-0x0007

变量c 的起始地址为 0x0008 %2

= 0 满足条件 占用两个字节 0x0008-0x0009

总共占用了10个字节的内存空间

3、圆整 结构体的有效对齐值是4 所以 总共占用的硬为(10+2)%4

= 0个字节 12个字节

再来看以下几个例子练习下:(以下例子是在VS2013上写的,默认成员内存对齐为8)

例子1:

输出:16

例子2:

093ed039dcaaac48800d22ecc9fb0d9a.png

输出:24

例子3:

33fd351782dac6516009c781675e70e1.png

输出:16

输出:12

附录:微软经典面试题:

#include

#pragma pack(8)

struct example1

{

short a;

long b;

};

struct example2

{

char c;

example1 struct1;

short e;

};

#pragma pack()

int main(int argc, char* argv[])

{

example2 struct2;

cout << sizeof(example1) << endl;

cout << sizeof(example2) << endl;

cout << (unsigned int)(&struct2.struct1) - (unsigned int)(&struct2) << endl;

return 0;

}输出:

8

16

4

在网络程序中,掌握这个概念可是很重要的喔,在不同平台之间(比如在Windows 和Linux之间)传递2进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙的出了一些错的······

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值