以前写过查看C++数据类型的字节数,但实际应用中我们更关心的是struct和class的大小。首先来看空类的大小,如下:
class VoidClass { };
运行程序,发现sizeof(VoidClass)结果为1。这里涉及到类的实例化的概念,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化后就有独一无二的地址了,所以空类的sizeof为1。
再来看class非空的情况。class非空的时候,其sizeof的大小主要取决于两方面因素,一是包含元素的大小及对齐问题,二是虚函数。首先来看一下C++的对界(Alignment)问题(摘自《Effective C++》):许多计算机体系结构要求特定的类型必须放在特定的内存地址上。例如它可能会要求指针的地址必须是4倍数(four-byte aligned)或8倍数(eight-byte aligned)。如果没有奉行这个约束条件,可能导致运行期硬件异常。有些体系结构比较仁慈,没有那么霸道,而是宣称如果对界条件获得满足,便提供较佳效率。如Intel
x86体系架构上的double可被对齐于任何byte边界,但如果它是8-byte齐位,其访问速度会快许多。一般来讲,32位的C++采用8字节对界来提高运行速度,所以编译器会尽量把数据放在它的对界上以提高内存命中率。对界是可以更改的,使用
#pragma pack(x)
宏可以改变编译器的对界方式,默认是8。C++固有类型的对界取编译器对界方式与自身大小中较小的一个。例如,指定编译器按2对界,int类型的大小是4,则int的对界为2和4中较小的2。在使用默认的对界方式下,因为几乎所有的数据类型都不大于默认的对界方式8(除了long double),所以所有的固有类型的对界方式可以认为就是类型自身的大小。对于复合数据类型,如union,struct和class的对齐方式为成员中对齐方式最大的成员的对齐方式。对于下面两个类:
class ClassA { char a; char b; int c; double d; }; class ClassB { char a; double d; int c; char b; };
运行程序,发现sizeof(ClassA)和sizeof(ClassB)的结果分别为16和24。其对应的空间存储结构为
但也不要认为它的对齐方式就是它的大小,看下面的例子:
class Sample1 { private: char a[8]; }; class Sample2 { private: double b; }; class Sample3 : public Sample1 { private: char c; }; class Sample4 : public Sample2 { private: char d; };
运行程序可以发现,它们的大小依次为8、8、9、16。虽然Sample1和Sample2大小都是8,但是Sample1的对齐方式是1,Sample是8,所以在Sample3和Sample4中才有这样的差异。
一般函数并不影响class的大小,但虚函数不是一般函数,来看看有虚函数的情况:
class BaseClass { public: BaseClass(); virtual ~BaseClass(); private: char p[8]; }; class DerivedClass : public BaseClass { private: char q; };
运行程序可以发现,它们的大小依次为12和16。可见加入虚函数后,类的结构也发生了改变,DerivedClass的大小不再像Sample3一样是9,而是16。这是因为C++类中有虚函数的时候有一个指向虚函数表的指针(vptr),在32位系统分配指针大小为4,则其对界方式也变成了4,所以才有这样的结果。
Update 2012-10-27:包含位域的sizeof计算http://blog.csdn.net/qinwang_gz/article/details/8112991
包含虚函数的sizeof计算http://blog.csdn.net/hackbuteer1/article/details/7883531