数据对齐/内存对齐 && 数据格式
一、数据对齐/内存对齐
字、双字、四字在自然边界上不须要在内存中对齐。
(什么叫做字?见第二部分)
对字、双字、四字来说,自然边界各自是偶数地址、能够被4整除的地址、能够被8整除的地址。
不管怎样。为了提高程序的性能,数据结构(尤其是栈)应该尽可能地在自然边界上对齐。
原因在于,为了訪问未对齐的内存。处理器须要做两次内存訪问;然而。对齐的内存仅须要一次訪问。
未对齐的:一个字或双字操作数跨越了4字节边界,或者一个四字操作数跨越了8字节边界,被觉得是未对齐的。须要两次总线周期訪问内存。
对齐的:一个字起始地址是奇数但却没有跨越字边界被觉得的对齐的,可以在一个总线周期中被訪问。
缺省情况下,编译器默认将结构、栈中的成员数据进行内存对齐。
对齐的三个规则:
1. 每一个成员分别按自己的方式对齐;
2. 复杂类型(如结构)的默认对齐方式是它最长的成员的对齐方式。(相当于把复杂类型展开)
3. 对齐后的长度必须是成员中最大的对齐參数的整数倍。(保证在处理数组时每一项都边界对齐)
样例1. 对于例如以下结构
struct TestStruct1 { char c1; short 2; char c2; int I; };如果c1的地址为0,则c1为00000000。s为00000002,c2为00000004,i为00000008。
2. 对于例如以下结构
struct TestStruct2 { char a; long b; }; struct TestStruct3 { char c; TestStruct2 d; long long e; };
TestStruct2中。成员a是1字节,默认按1字节对齐;成员b是4字节,默认按4字节对齐。所以sizeof(TestStruct2)为8.
TestStruct3中,成员c是按1字节对齐;d是个结构,它是8字节,可是结构的默认对齐方式是其全部成员使用的对齐參数中最大的一个。所以d是按4字节对齐。e是8字节,默认按8字节对齐。内存布局例如以下:(*表示空暇内存。1表示使用内存)
TestStruct3的内存布局: 1***,1***,1111,****。11111111
c d.a d.b e
另:对于typedef char Array3[3],Array3这样的类型的对齐方式还是按1字节对齐。而不是按它的长度。
參考:《C语言深度剖析》第3章预处理,#pragma pack
#pragma pack(n) …//此中间的部分按指定对齐方式对齐 #pragma pack()可是成员对齐有一个重要条件。即每一个成员按自己的方式对齐。
(也就是说,尽管指定了按n字节对齐,但并非全部的成员都是以n字节对齐。)对齐规则是,每一个成员按其类型的对齐參数(一般是这个类型的大小)和指定对齐參数中的较小的一个对齐,而且结构的长度必须为所用过的全部对齐參数的整数倍。不够就补空字节。
二、数据格式
由于是从16位体系结构扩展成32位的。Intel用术语“字”(word)表示16位数据类型。
由于。32位数为“双字”(double words),64位数为“四字”(quad words)。
对照——字长
每台计算机都有一个字长(word size),指明整数和指针数据的标称大小。
由于虚拟地址是以这种一个字来编码(这句话我的理解是。字长大小的各个位通过01变化来表示虚拟地址),所以字长决定的最重要的系统參数就是虚拟地址空间的最大大小。
也就是说,对于一个字长为w位的机器而言。虚拟地址的范围为0~2^w-1,程序最多訪问2^w个字节。
现在大多数计算机的字长都是32位。这就限定了虚拟地址空间为4GB字节。
C声明 |
char |
short |
int |
long int |
long long |
指针 |
float |
double |
32位机器 |
1 |
2 |
4 |
4 |
8 |
4 |
4 |
8 |
64位机器 |
1 |
2 |
4 |
8 |
8 |
8 |
4 |
8 |
能够看到,
- 短整数分配2字节。
- 不加限定的int为4字节,
- “长”整数使用机器的全字长(32位为4字节,64位为8字节)。
- ISO C99引入的“长长”整数使用8字节,即64位整数。(对于32位机器。编译器必须把这样的数据类型的操作编译成运行一系列32位操作的代码。)
- 指针,使用机器的全字长。
- 对于浮点数,单精度和双精度分别使用4字节和8字节。
关于“字长”和“字”
字长,是指出计算机整数和指针数据的标称大小,可能是32位,也可能是64位等等;而,字指的就是16位。由于双字是32位、四字是64位。注意不要弄混“字长”和“字”的概念。“字长”的意思并非”字“的长度。而是指计算机整数和指针数据的标称大小。