1、C+中的 sizeof 关键字详解1、什么是 sizeof 首先看一下 sizeof 在 msdn 上的定义:The sizeof keyword gives the amount of storage, in bytes, associated with a variable or a type (including aggregate types). This keyword returns a value of type size_t.看到 return 这个字眼,是不是想到了函数?错了,sizeof 不是一个函数,你见过给一个函数传参数,而不加括号的吗?sizeof 可以,所以 siz
2、eof 不是函数。网上有人说sizeof 是一元操作符,但是我并不这么认为,因为 sizeof 更像一个特殊的宏,它是在编译阶段求值的。举个例子:coutusing namespace std;int Sum(int i)int sumofi = 0;for (int j = 0; j using namespace std;int Sum(int *i, unsigned int n)int sumofi = 0;for (int j = 0; j n; j+)sumofi += ij;return sumofi;int main()int allAges = 21, 22, 22, 19,
3、 34, 12;coutSum(i, sizeof(allAges)/sizeof(int)endl;system(“pause“);return 0;7、字符串的 sizeof 和 strlen考虑下面的问题:char a = “abcdef“;char b20 = “abcdef“;string s = “abcdef“;coutstrlen(a)endl; / 6,字符串长度coutsizeof(a)endl; / 7,字符串容量coutstrlen(b)endl; / 6,字符串长度coutstrlen(b)endl; / 20,字符串容量coutsizeof(s)endl; / 12
4、, 这里不代表字符串的长度,而是 string 类的大小coutstrlen(s)endl; / 错误!s 不是一个字符指针。a1 = 0;coutstrlen(a)endl; / 1coutsizeof(a)endl; / 7,sizeof 是恒定的strlen 是寻找从指定地址开始,到出现的第一个 0 之间的字符个数,他是在运行阶段执行的,而 sizeof 是得到数据的大小,在这里是得到字符串的容量。所以对同一个对象而言,sizeof 的值是恒定的。string 是 C+类型的字符串,他是一个类,所以 sizeof(s)表示的并不是字符串的长度,而是类 string 的大小。strlen(
5、s)根本就是错误的,因为strlen 的参数是一个字符指针,如果想用 strlen 得到 s 字符串的长度,应该使用sizeof(s.c_str(),因为 string 的成员函数 c_str()返回的是字符串的首地址。实际上,string 类提供了自己的成员函数来得到字符串的容量和长度,分别是 Capacity()和Length()。string 封装了常用了字符串操作,所以在 C+开发过程中,最好使用 string 代替 C 类型的字符串。8、从 union 的 sizeof 问题看 cpu 的对界考虑下面问题:(默认对齐方式)union udouble a;int b;union u2c
6、har a13;int b;union u3char a13;char b;coutsizeof(u)endl; / 8coutsizeof(u2)endl; / 16coutsizeof(u3)endl; / 13都知道 union 的大小取决于它所有的成员中,占用空间最大的一个成员的大小。所以对于 u 来说,大小就是最大的 double 类型成员 a 了,所以 sizeof(u)=sizeof(double)=8。但是对于 u2 和 u3,最大的空间都是 char13类型的数组,为什么 u3 的大小是 13,而 u2 是 16 呢?关键在于 u2 中的成员 int b。由于 int 类型成
7、员的存在,使 u2 的对齐方式变成 4,也就是说,u2 的大小必须在 4 的对界上,所以占用的空间变成了 16(最接近 13的对界) 。结论:复合数据类型,如 union,struct,class 的对齐方式为成员中对齐方式最大的成员的对齐方式。顺便提一下 CPU 对界问题,32 的 C+采用 8 位对界来提高运行速度,所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的,使用#pragma pack(x)宏可以改变编译器的对界方式,默认是 8。C+固有类型的对界取编译器对界方式与自身大小中较小的一个。例如,指定编译器按 2 对界,int 类型的大小是 4,则 int 的对界
8、为 2 和 4中较小的 2。在默认的对界方式下,因为几乎所有的数据类型都不大于默认的对界方式8(除了 long double) ,所以所有的固有类型的对界方式可以认为就是类型自身的大小。更改一下上面的程序:#pragma pack(2)union u2char a13;int b;union u3char a13;char b;#pragma pack(8)coutsizeof(u2)endl; / 14coutsizeof(u3)endl; / 13由于手动更改对界方式为 2,所以 int 的对界也变成了 2,u2 的对界取成员中最大的对界,也是 2 了,所以此时 sizeof(u2)=14
9、。结论:C+固有类型的对界取编译器对界方式与自身大小中较小的一个。9、struct 的 sizeof 问题因为对齐问题使结构体的 sizeof 变得比较复杂,看下面的例子:(默认对齐方式下)struct s1char a;double b;int c;char d; ;struct s2char a;char b;int c;double d;coutsizeof(s1)endl; / 24coutsizeof(s2)endl; / 16同样是两个 char 类型,一个 int 类型,一个 double 类型,但是因为对界问题,导致他们的大小不同。计算结构体大小可以采用元素摆放法,我举例子说明
10、一下:首先,CPU判断结构体的对界,根据上一节的结论,s1 和 s2 的对界都取最大的元素类型,也就是double 类型的对界 8。然后开始摆放每个元素。对于 s1,首先把 a 放到 8 的对界,假定是 0,此时下一个空闲的地址是 1,但是下一个元素 d 是 double 类型,要放到 8 的对界上,离 1 最接近的地址是 8 了,所以 d 被放在了8,此时下一个空闲地址变成了 16,下一个元素 c 的对界是 4,16 可以满足,所以 c 放在了 16,此时下一个空闲地址变成了 20,下一个元素 d 需要对界 1,也正好落在对界上,所以 d 放在了 20,结构体在地址 21 处结束。由于 s1
11、 的大小需要是 8 的倍数,所以 21-23 的空间被保留,s1 的大小变成了 24。对于 s2,首先把 a 放到 8 的对界,假定是 0,此时下一个空闲地址是 1,下一个元素的对界也是 1,所以 b 摆放在 1,下一个空闲地址变成了 2;下一个元素 c 的对界是 4,所以取离 2 最近的地址 4 摆放 c,下一个空闲地址变成了 8,下一个元素 d 的对界是 8,所以d 摆放在 8,所有元素摆放完毕,结构体在 15 处结束,占用总空间为 16,正好是 8 的倍数。这里有个陷阱,对于结构体中的结构体成员,不要认为它的对齐方式就是他的大小,看下面的例子:struct s1char a8;struct s2double d;struct s3s1 s;