您的位置:首页 > 其它

c的字节对齐之总结

2011-11-28 22:52 597 查看
三个概念:

1,自然对齐值:

如果一个变量的内存地址正好在它的长度的整数倍的位置,该变量就是自然对齐的。如在32位CPU下,一个整型变量的地址为0x00000004,则它是自然对齐的。

需要字节对齐(自然对齐)的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐的,而是为0x00000002,则CPU需要访问两次内存才能取得该变量的值:第一次取0x00000002-0x00000003的一个short,第二次取0x00000004-0x00000005的一个short,然后组合得到数据。如果该变量的地址为0x00000003,则需要访问三次内存:第一次为char,第二次为short,第三次为char,然后组合得到数据。而自然对齐则只要一次就可以取出数据。一些系统如sparc,对字节对齐要求非常严格,取未对齐的数据会发生错误。

32位机器上基本数据类型的长度如下:(自然对齐值)

char:1 short:2 int:4 long:4 float:4 double:8

结构体、联合、类的自然对齐值等于其成员中自然对齐值最大的那个值。

2,指定对齐值:通过#pragma pack (value)等指令指定的字节对齐值。未指定时一般默认为4。

3,有效对齐值:等于自然对齐值和指定对齐值二者中较小的值。

数据的最终存放地址由有效对齐值决定。有效对齐值N表示“对齐在N上”,即该数据的“存放起始地址 % N = 0”。结构体(联合、类)的成员变量按声明的先后顺序对齐存放,结构体本身也要根据自身的有效对齐值填充取整,即结构体占用的总长度需要是结构体有效对齐值的整数倍。

如果在编程的时候要考虑节约空间的话,基本原则就是按照类型大小“从小到大”声明结构体中的变量,尽量减少中间的填补空间。也可以显式地进行填充对齐,如插入reserved成员:

struct A

{

char a;

char reserved[3]; // 当然不加编译器也会自动为我们对齐

int b;

}

示例程序:

#include <stdio.h>

struct S1

{

char x1;

short x2;

float x3;

char x4;

};

#pragma pack(1) //让编译器对这个结构作1字节对齐

struct S2

{

char x1;

short x2;

float x3;

char x4;

};

#pragma pack() //取消1字节对齐,恢复为默认4字节对齐

struct A

{

int a;

char b;

short c;

};

struct B

{

char b;

int a;

short c;

};

#pragma pack (2) /*指定按2字节对齐*/

struct C

{

char b;

int a;

short c;

};

#pragma pack () /*取消指定对齐,恢复缺省对齐*/

#pragma pack (1) /*指定按1字节对齐*/

struct D

{

char b;

int a;

short c;

};

#pragma pack () /*取消指定对齐,恢复缺省对齐*/

struct E

{

char b;

double d;

};

/* 32位机器,vs2008,mingw */

int main()

{

printf("sizeof(test): %u\n", sizeof(S1)); // -> 12

printf("sizeof(test1): %u\n", sizeof(S2)); // -> 8

printf("sizeof(A): %u\n", sizeof(A)); // -> 8

printf("sizeof(B): %u\n", sizeof(B)); // -> 12

printf("sizeof(C): %u\n", sizeof(C)); // -> 8

printf("sizeof(D): %u\n", sizeof(D)); // -> 7

printf("sizeof(E): %u\n", sizeof(E)); // -> 16

return 0;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: