首先来看sizeof运算符:
The result of the sizeof operator is of type size_t, an integral type defined in the include file STDDEF.H. This operator allows you to avoid specifying machine-dependent data sizes in your programs.
sizeof 运算符返回一条表达式或一个类型的字节数,返回值为 size_t 类型的常量表达式,size_t 是包含文件 STDDEF.H 中定义的一个整数类型。
sizeof 运算形式:
- sizeof(type) :类型名称。 若要将 sizeof 用于类型名称,则该名称必须用括号括起。如
sizeof(char)
。 - sizeof expr :一个表达式。 括号可加可不加,返回表达式结果类型的大小,并不实际计算运算对象的值。如
sizeof(a) sizeof a
。
sizeof 返回操作数的所占空间大小,简单的就不赘述了,常规的
sizeof(char) = 1
sizeof(int) = 4 //跟环境有关
sizeof(数组) = 数组元素类型大小 X 数组元素个数
sizeof array / sizeof array[0] = array中元素个数
值得注意的2点:
- 当数组作为参数传入一个函数时,在函数内部使用 sizeof 并不能得到元素个数,传入函数的只是一个数组元素类型的指针,sizeof得到的结果应该是指针的大小。
- sizeof(string) 或 sizeof str /*str为string类型的对象*/ 并不能得到字符串的长度或所占空间大小,因为string是一个字符串的类型,所以sizeof str 表示的并不是该具体字符串的长度,而是类string的大小。
PS:在我这里(VS2013 win32)中,sizeof(string)=28,我想应该跟string类中内部成员以及basic_string类的内部实现细节等有关,也有编译器中sizeof(string)=4,因为string可以看作是一个指针。
当 sizeof 运算符应用到 class、struct 或 union 类型时,结果不一定对应于通过将各个成员空间简单相加所计算出的大小,其中涉及到字节对齐的问题。 编译器选项 /Zp 和 #pack pragma 会影响成员的对齐边界(默认为8)。
对齐原则:
- 结构体变量的首地址能够被其最宽数据类型成员的大小整除。编译器在为结构体变量开辟空间时,首先找到结构体中最宽的数据类型,然后寻找内存地址能被该数据类型大小整除的位置,这个位置作为结构体变量的首地址。
- 开辟空间时会按照结构体中顺序依次开辟,如果空间紧张,可以把float、double等较宽类型放在结构体的开始或者最后。
- 最宽数据类型的大小作为对齐标准。结构体每个成员相对结构体首地址的偏移量(offset)都是每个成员本身大小的整数倍,编译器在为结构体成员开辟空 间时,首先检查预开辟空间的地址相对于结构体首地址的偏移量是否为该成员大小的整数倍,若是,则存放该成员;若不是,则填充若干字节,以达到整数倍的要求。最后一个成员末尾也会填充字节使得所占空间大小是最宽数据类型大小的整数倍。
直接举栗子:
typedef union
{
int a[5];
char b;
} UNION_DATA;
struct STRUC_DATA
{
UNION_DATA a;
double b;
int c;
};
struct STRUC_VOID
{
};
struct DATA2
{
char a[5];
int c[3];
pair<int, double> d;
};
逐条解释结果(结果基于VS2013,win32):
1. sizeof(UNION_DATA) 20:
union 中所有成员都共享同一个内存位置,即在任何时间,联合都不能包含来自其成员列表的多个对象。 所以无论它有多少成员,始终只使用足以存储最大成员的内存。
所以,大小为int[5],即20字节。
2. sizeof(STRUC_DATA) 40
最长为double类型,8字节,所以首先int[5],20字节,后面double8字节放不下,所以填充4字节,再加double8字节,最后int4字节,填充4字节对齐,所以应该是20+ 4 +8+4+ 4 = 40字节。
3. sizeof(STRUC_VOID) 1
空结构体占1个字节,同时,静态数据成员存放于静态区,sizeof不计算,若只有静态数据成员也相当于空。
4. sizeof(DATA2) 40
最长为double类型,所以char[5]后int占4字节,不能存放在后面,所以填充3字节,然后int[3]占12字节,后面pair