C语言中内存对齐方式

来源:互联网 发布:mac终端格式化整个磁盘 编辑:程序博客网 时间:2024/06/01 10:40

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

为什么需要内存对齐?

1、平台原因(移植原因):不是所有的硬件平台都能访问任意地址上的任意数据的。某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。
2、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。

内存对齐怎么计算?

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

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

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

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

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

#include <iostream>#include<stdio.h>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;}

输出结果:


分析过程:

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 <iostream>#include<stdio.h>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:


输出:24

例子3:


输出:16


输出:12

附录:微软经典面试题:

#include <iostream.h>#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进制流(比如结构体),那么在这两个平台间必须要定义相同的对齐方式,不然莫名其妙的出了一些错的······

0 0
原创粉丝点击