[C/C++]结构体大小的计算方法
2013-07-05 11:57
375 查看
通常情况下,由于地址对齐(alignment)的需要,结构体各成员之间或结构体的尾部需要添补一些空白字节(padding),因而结构体的大小并不一定等于各成员大小之和。包含相同成员的结构体,如果成员声明的顺序不同,其占用的内存空间也可能不同。尽管在程序中可以利用sizeof获取当前编译条件下结构体所占内存空间的大小,但深入了解结构体中成员对齐所遵循的规则也很有必要。
首先需要说明一下对齐的概念。结构体成员的对齐是指成员相对于结构体首地址的偏移量(offset)应该被2^n整除,n通常取0、1、2、3、4,称此时的对齐方式为2^n-byte对齐。例如2-byte对齐的时候,成员的偏移量只能是0、2、4……而4-byte对齐的时候偏移量只能是0、4、8……在C语言中,查看成员的偏移量可以利用stddef.h中定义的宏offsetof(T, member),offsetof的定义如下:
#define offsetof(T, member) ((size_t)&((T *)0)->member)
结构体中各成员以什么方式对齐与成员的大小有关,成员大小为a则进行a-byte对齐,即成员的偏移量应该被成员的大小整除。例如short类型的成员其偏移量必须是2的整数倍,double类型的成员其偏移量必须是8的整数倍。一个简单的例子如下所示:
struct sExample1
{
short member1; //偏移量为0,能够被2整除
//member1后添加6个字节的padding
double member2; //偏移量必须为8才能被8整除
};
sExample1中member1为short类型,大小为2,采用2-byte对齐的方式,偏移量为0即可。member2为double类型,大小为8,需满足8-byte对齐的条件,因此其偏移量只能为8。在member1和member2之间添加6个字节的padding,因此sExample1的大小为16。
除了在成员之间添加padding以外,在结构体的尾部也可能添加padding,以使得结构体的大小能够被最大成员的大小整除。例如:
struct sExample2
{
double member1;
short member2;
//member2后添加6个字节的padding
};
sExample2中,虽然member1和member2之间没有加入padding,但由于其最大成员(member1)的大小为8个字节,因此在member2之后添加了6个字节的padding,以使得结构体的大小能够被8整除。sExample2的大小仍然为16。
在VC的编译器中,通过#pragma pack可以限制添加padding的字节数。例如在定义结构体之前添加#pragma pack(n),则编译器为某个成员添加的padding的字节数不能超过n减去该成员的大小,这里n的取值可以是1、2、4、8、16。例如:
#pragma pack(4)
struct sExample3
{
short member1;
//member1后添加2个字节的padding
double member2;
};
#pragme pack()
由于添加了#pragma pack(4),member1后添加padding的字节数不能超过4-sizeof(short),即2字节。例中#pragma pack()将padding的字节限制设置成默认值。
MSDN提供了一些计算结构体大小的典型例子,例如:
struct sExample4
{
short member; //offsetof(sExample4, member) == 0
}; //sizeof(sExample4) == 2
struct sExample5
{
int member1; //offsetof(sExample5, member1) == 0
double member2; //offsetof(sExample5, member2) == 8
short member3; //offsetof(sExample5, member3) == 16
}; //sizeof(sExample5) == 24
struct sExample6
{
char member1; //offsetof(sExample6, member1) == 0
short member2; //offsetof(sExample6, member2) == 2
char member3; //offsetof(sExample6, member3) == 4
int member4; //offsetof(sExample6, member4) == 8
}; //sizeof(sExample6) == 12
#pragma pack(4)
struct sExample7
{
int member1; //offsetof(sExample7, member1) == 0
double member2; //offsetof(sExample7, member2) == 4
short member3; //offsetof(sExample7, member3) == 12
}; //sizeof(sExample5) == 16
#pragma pack()
#pragma pack(1)
struct sExample8
{
char member1; //offsetof(sExample8, member1) == 0
short member2; //offsetof(sExample8, member2) == 1
char member3; //offsetof(sExample8, member3) == 3
int member4; //offsetof(sExample8, member4) == 4
}; //sizeof(sExample6) == 8
#pragma pack()
References
http://msdn.microsoft.com/en-us/library/aa290049(VS.71).aspx
http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
http://msdn.microsoft.com/en-us/library/71kf49f1.aspx
首先需要说明一下对齐的概念。结构体成员的对齐是指成员相对于结构体首地址的偏移量(offset)应该被2^n整除,n通常取0、1、2、3、4,称此时的对齐方式为2^n-byte对齐。例如2-byte对齐的时候,成员的偏移量只能是0、2、4……而4-byte对齐的时候偏移量只能是0、4、8……在C语言中,查看成员的偏移量可以利用stddef.h中定义的宏offsetof(T, member),offsetof的定义如下:
#define offsetof(T, member) ((size_t)&((T *)0)->member)
结构体中各成员以什么方式对齐与成员的大小有关,成员大小为a则进行a-byte对齐,即成员的偏移量应该被成员的大小整除。例如short类型的成员其偏移量必须是2的整数倍,double类型的成员其偏移量必须是8的整数倍。一个简单的例子如下所示:
struct sExample1
{
short member1; //偏移量为0,能够被2整除
//member1后添加6个字节的padding
double member2; //偏移量必须为8才能被8整除
};
sExample1中member1为short类型,大小为2,采用2-byte对齐的方式,偏移量为0即可。member2为double类型,大小为8,需满足8-byte对齐的条件,因此其偏移量只能为8。在member1和member2之间添加6个字节的padding,因此sExample1的大小为16。
除了在成员之间添加padding以外,在结构体的尾部也可能添加padding,以使得结构体的大小能够被最大成员的大小整除。例如:
struct sExample2
{
double member1;
short member2;
//member2后添加6个字节的padding
};
sExample2中,虽然member1和member2之间没有加入padding,但由于其最大成员(member1)的大小为8个字节,因此在member2之后添加了6个字节的padding,以使得结构体的大小能够被8整除。sExample2的大小仍然为16。
在VC的编译器中,通过#pragma pack可以限制添加padding的字节数。例如在定义结构体之前添加#pragma pack(n),则编译器为某个成员添加的padding的字节数不能超过n减去该成员的大小,这里n的取值可以是1、2、4、8、16。例如:
#pragma pack(4)
struct sExample3
{
short member1;
//member1后添加2个字节的padding
double member2;
};
#pragme pack()
由于添加了#pragma pack(4),member1后添加padding的字节数不能超过4-sizeof(short),即2字节。例中#pragma pack()将padding的字节限制设置成默认值。
MSDN提供了一些计算结构体大小的典型例子,例如:
struct sExample4
{
short member; //offsetof(sExample4, member) == 0
}; //sizeof(sExample4) == 2
struct sExample5
{
int member1; //offsetof(sExample5, member1) == 0
double member2; //offsetof(sExample5, member2) == 8
short member3; //offsetof(sExample5, member3) == 16
}; //sizeof(sExample5) == 24
struct sExample6
{
char member1; //offsetof(sExample6, member1) == 0
short member2; //offsetof(sExample6, member2) == 2
char member3; //offsetof(sExample6, member3) == 4
int member4; //offsetof(sExample6, member4) == 8
}; //sizeof(sExample6) == 12
#pragma pack(4)
struct sExample7
{
int member1; //offsetof(sExample7, member1) == 0
double member2; //offsetof(sExample7, member2) == 4
short member3; //offsetof(sExample7, member3) == 12
}; //sizeof(sExample5) == 16
#pragma pack()
#pragma pack(1)
struct sExample8
{
char member1; //offsetof(sExample8, member1) == 0
short member2; //offsetof(sExample8, member2) == 1
char member3; //offsetof(sExample8, member3) == 3
int member4; //offsetof(sExample8, member4) == 4
}; //sizeof(sExample6) == 8
#pragma pack()
References
http://msdn.microsoft.com/en-us/library/aa290049(VS.71).aspx
http://msdn.microsoft.com/en-us/library/2e70t5y1.aspx
http://msdn.microsoft.com/en-us/library/71kf49f1.aspx
相关文章推荐
- C++ 类的空间大小计算基本方法
- C++字节对齐与结构体大小计算
- C++中类的大小计算方法总结
- 结构体大小的计算方法
- 结构体大小的计算 用最简单的方法,通俗易懂的方法计算结构体大小
- 结构体大小的计算 用最简单的方法,通俗易懂的方法计算结构体大小
- C++中类的大小计算方法总结《网络+总结》
- c++中利用sizeof运算符计算结构体大小问题探讨
- C++字节对齐与结构体大小计算
- 内存对齐(计算结构体大小)方法
- C/C++结构体大小的计算方法(Windows 32为处理器)
- 结构体大小的计算 用最简单的方法,通俗易懂的方法计算结构体大小
- 结构体大小计算方法
- 结构体大小的计算及设置内存字节对齐数原理理解
- c/c++在windows下获取时间和计算时间差的几种方法总结
- 数据结构大小的计算-sizeof
- C中含位域结构体大小的计算
- Java 文件大小以M为单位计算方法
- C++中虚函数工作原理和(虚)继承类的内存占用大小计算
- C/C++多种方法获取文件大小