规定各成员变量存放的起始地址相对于结构的起始地址的偏移量必须为该“变量的类型”或者指定对齐系数所占用的字节数的倍数,当变量类型和指定系数不同时,取小的。整个结构大小按照以上对齐计算,但必须是最大类型大小或者指定对齐系数的整数倍,也就是最后一个成员变量要圆整,当最大类型大小和指定对齐系数不一致的情况,取小的。当成员变量本身是结构体的时候,不能用整个struct大小计算起始地址,而应该用结构体中最大类型大小代替整个struct变量计算起始地址。
如:
typedef struct {char x;
int y[5];
char z;
}struct_m; //28
typedef struct {
char x;
double y[5];
char z;
}struct_n; //56
typedef struct{
char x;
struct_m f; //起始地址必须为最大类型-整形的整数倍,即int的整数倍,4
char y;
struct_n g; //起始地址必须为struct_n中double的整数倍,40
}struct_o;
一.基本数据的长度(32位windows平台)
char:1(有符号无符号同)
short:2(有符号无符号同)
int:4(有符号无符号同)
long:4(有符号无符号同)
float:4
double:8
二.对齐的作用和原因:
各个硬件平台对存储空间的处理上有很大的不同。一些平台对某些特定类型的数据只能从某些特定地址开始存取。比如有些架构的CPU在访问 一个没有进行对齐的变量的时候会发生错误,那么在这种架构下编程必须保证字节对齐.其他平台可能没有这种情况,但是最常见的是如果不按照适合其平台要求对 数据存放进行对齐,会在存取效率上带来损失。比如有些平台每次读都是从偶地址开始,如果一个int型(假设为32位系统)如果存放在偶地址开始的地方,那 么一个读周期就可以读出这32bit,而如果存放在奇地址开始的地方,就需要2个读周期,并对两次读出的结果的高低字节进行拼凑才能得到该32bit数 据。显然在读取效率上下降很多。
三.一些常见的和需要注意的sizeof
char* a= "abc"; //sizeof(a)=4
==============================================
char b[100]; //sizeof(b)=100;
==============================================
char* c=(char*)malloc(100); //sizeof(c)=100
==============================================
char d[] = "abc"; //sizeof(d)=4
==============================================
int e[100]; //求数组的元素个数int c2 = sizeof( e ) / sizeof( e[0] ); // 总长度/第一个元素的长度
==============================================
void foo3(char f[3])
{
int c3 = sizeof( f); // c3 =4
}
==============================================
void foo4(char g[])
{
int c4 = sizeof( g); // c4 =4
}
==============================================
int a = 1, b =2; 执行sizeof (a = b)
之后为什么a=1, 而不是2. 为什么没有执行赋值操作? (淘宝笔试题)
(1)sizeof (type-name) 是求变量类型的大小 ,在编译期执行 ,因为sizeof 是在编译期内执行而不是在运行期 所以 sizeof (a = b) 是不会运行a = b 这个操作的。
(2)sizeof是一个运算符而不是一个函数。 编译器会查符号表求出值大小,而不会执行里面的表达式
(3)sizeof 是如何来看待 a = b的?
sizeof 是按照类型计算字节的,与值无关。 在编译器中,上句等价于 sizeof( int = int ),
结果按照“左值”计算字节数
你可以试试
int a=1;
double b=2.0;
cout < <sizeof(a=b); //等价于 sizeof(int= double) 自动cast
cout < <sizeof(b=a); //等价于 sizeof(double = int)
一个结果是 4,一个是8
(4)sizeof(1) 1 是int类型 所以4
sizeof(1.1) 1.1 为double 所以8
当然这个根据机器不同结果也不一样
四.结构体和类的规则
1.数据类型自身的对齐值:
对于char型数据,其自身对齐值为1,对于short型为2,对于int,float,double类型,其自身对齐值为4,单位字节。
2.结构体或者类的自身对齐值:其成员中自身对齐值最大的那个值。
3.指定对齐值:#pragma pack (value)时的指定对齐值value。
4.数据成员、结构体和类的有效对齐值:自身对齐值和指定对齐值中小的那个值。
上面包含两层意思:
一是结构体(类)里面的成员地址要按照自身的大小对齐,也就是addressof(struct.number)%sizeof(struct.number)=0;对于结构体内部为复杂类型的成员(例如结构体,数组等),其地址以其自身的最大成员大小对其。
二是整个结构体(类)要按照成员中自身对齐值最大(N)的那个值进行对齐,也就是sizeof(struct)%N=0。这里的N为最大的基本类型,对于复杂类型看的是其中最大成员大小,而不是复杂类型的大小。
五.例子
- #include "stdio.h"
- #include "stddef.h"
- //#define offsetof(s,m) (size_t)&(((s *)0)->m)
- typedef struct {
- char a; // 1 byte
- int b; // 4 bytes
- short c; // 2 bytes
- char d; // 1 byte
- } struct_a;
- typedef struct {
- char a; // 1 byte
- char _pad0[3]; // padding to put 'b' on 4-byte boundary
- int b; // 4 bytes
- short c; // 2 bytes
- char d; // 1 byte
- char _pad1[1]; // padding to make sizeof(x_) multiple of 4
- }struct_b;
- //struct_x强制 模1 对齐.
- # pragma pack (1)
- typedef struct
- {
- char a; // 1 byte
- int b; // 4 bytes
- short c; // 2 bytes
- } struct_c;
- # pragma pack ()
- //struct_x被强制 模2 对齐.
- # pragma pack (2)
- typedef struct
- {
- char a; // 1 byte
- int b; // 4 bytes
- short c; // 2 bytes
- } struct_d;
- # pragma pack ()
- //struct_x被强制 模8对齐.
- # pragma pack (8)
- typedef struct
- {
- char a; // 1 byte
- int b; // 4 bytes
- short c; // 2 bytes
- } struct_e;
- # pragma pack ()
- typedef struct
- {
- char a;
- short b;
- char c;
- }struct_f;
- typedef struct
- {
- char a;
- char c;
- short b;
- }struct_g;
- typedef struct
- {
- char b;
- int a;
- short c;
- }struct_h;
- typedef struct{
- unsigned char incon: 8; /*incon占用低字节的0~7共8位*/
- unsigned char txcolor: 4;/*txcolor占用高字节的0~3位共4位*/
- unsigned char bgcolor: 3;/*bgcolor占用高字节的4~6位共3位*/
- unsigned char blink: 1; /*blink占用高字节的第7位*/
- }struct_i;
- typedef struct{ //整个结构体要以2(sizeof(unsigned short))对齐
- unsigned short incon: 8;
- unsigned short txcolor: 4;
- unsigned short bgcolor: 3;
- unsigned short blink: 1;
- }struct_j;
- typedef struct{ //整个结构体要以4(sizeof(unsigned int))对齐
- unsigned int incon: 8;
- unsigned int txcolor: 4;
- unsigned int bgcolor: 3;
- unsigned int blink: 1;
- }struct_k;
- typedef struct{ //整个结构体要以4(sizeof(unsigned int))对齐
- unsigned incon: 8;
- unsigned txcolor: 4;
- unsigned bgcolor: 3;
- unsigned blink: 1;
- }struct_l;
- typedef struct {
- char x;
- int y[5];
- char z;
- }struct_m;
- typedef struct {
- char x;
- double y[5];
- char z;
- }struct_n;
- typedef struct{
- char x;
- struct_m f;
- char y;
- struct_n g;
- }struct_o;
- class CLASS_A{
- char x;
- void func();
- };
- class CLASS_B{
- char x;
- virtual void func();
- };
- class CLASS_C{
- char x;
- char y;
- virtual void func();
- };
- class CLASS_D{
- char x;
- char* z;
- char y;
- virtual void func();
- };
- class CLASS_E{
- char x;
- CLASS_A a;
- void func();
- };
- class CLASS_F{
- char x;
- int y;
- };
- class CLASS_G{
- char x;
- CLASS_F f;
- void func();
- };
- class CLASS_H{
- char x;
- CLASS_F* f;
- void func();
- };
- class CLASS_I{
- char x;
- virtual void func();
- virtual void func1();
- };
- #define NAMEOF(x) #x
- #define PRINT_SIZEOF(x) do{printf("sizeof(%s)=%d/n",NAMEOF(x),sizeof(x));}while(0)
- int main(){
- PRINT_SIZEOF(struct_a);
- PRINT_SIZEOF(struct_b);
- PRINT_SIZEOF(struct_c);
- PRINT_SIZEOF(struct_d);
- PRINT_SIZEOF(struct_e);
- PRINT_SIZEOF(struct_f);
- PRINT_SIZEOF(struct_g);
- PRINT_SIZEOF(struct_h);
- PRINT_SIZEOF(struct_i);
- PRINT_SIZEOF(struct_j);
- PRINT_SIZEOF(struct_k);
- PRINT_SIZEOF(struct_l);
- PRINT_SIZEOF(struct_m);
- PRINT_SIZEOF(struct_n);
- PRINT_SIZEOF(struct_o);
- printf("offsetof struct_n.f=%d/n", offsetof(struct_o, f));
- printf("offsetof struct_n.g=%d/n", offsetof(struct_o, g));
- PRINT_SIZEOF(CLASS_A);
- PRINT_SIZEOF(CLASS_B);
- PRINT_SIZEOF(CLASS_C);
- PRINT_SIZEOF(CLASS_D);
- PRINT_SIZEOF(CLASS_E);
- PRINT_SIZEOF(CLASS_F);
- PRINT_SIZEOF(CLASS_G);
- PRINT_SIZEOF(CLASS_H);
- PRINT_SIZEOF(CLASS_I);
- return 0;
- }
六.例子结果
sizeof(struct_a)=12
sizeof(struct_b)=12
sizeof(struct_c)=7
sizeof(struct_d)=8
sizeof(struct_e)=12
sizeof(struct_f)=6
sizeof(struct_g)=4
sizeof(struct_h)=12
sizeof(struct_i)=2
sizeof(struct_j)=2
sizeof(struct_k)=4
sizeof(struct_l)=4
sizeof(struct_m)=28
sizeof(struct_n)=56
sizeof(struct_o)=96
offsetof struct_n.f=4
offsetof struct_n.g=40
sizeof(CLASS_A)=1
sizeof(CLASS_B)=8
sizeof(CLASS_C)=8
sizeof(CLASS_D)=16
sizeof(CLASS_E)=2
sizeof(CLASS_F)=8
sizeof(CLASS_G)=12
sizeof(CLASS_H)=8
sizeof(CLASS_I)=8
七.显示class的对象布局
VC8的隐含编译项/d1reportSingleClassLayout和/d1reportAllClassLayout可以看对象的布局。例如你需要看CLASS_G的对象布局,就在编译参数里面加上/d1reportSingleClassLayoutCLASS_G。更加详细的介绍请参考下面的第4个网址。下面是CLASS_G的对象布局:
class CLASS_G size(12):
+---
0 | x
| <alignment member> (size=3)
4 | CLASS_F f
+---
八.参考:
http://blog.chinaunix.net/u/20828/showart_438003.html
http://www.yuanma.org/data/2006/0723/article_1213.htm
http://blog.sina.com.cn/s/blog_59b189220100a49h.html
http://www.cnblogs.com/neoragex2002/archive/2007/11/01/VC8_Object_Layout_Secret.html