天天看点

浅说c/c++的sizeof

1 初识sizeof,sizeof的定义

sizeof是c/c++中的一个操作符,用于返回一个对象或者类型所占用的内存字节数。sizeof返回值的类型为为size_t,一般在头文件中定义为 typedef unsigned int size_t。sizeof返回值的大小依赖于编译系统,下面我们要讨论的都是限定在32位编译系统下的。

2.小试牛刀,sizeof的使用方法

2.1 用于数据类型,如:

2.2 用于对象,如:

int number = ; 

sizeof(number); // OK

sizeof number; // OK
           

PS:对于类型来说,必须用()包住,如:

所以为了统一,在一般情况下,即使是对于对象,我们也用()包住。实际上,sizeof计算单个对象的大小也是转换成对象类型的计算 。需要注意的是,sizeof 操作符不能作用于函数,不完全类型或位字段(bit-field)。如 :

int test1()
 {
      int number = ;

      return number;
 }

 void test2()
 {
       //do nothing
 }

 sizeof( test1 );//ERROR

 sizeof( test2() );//ERROR

 sizeof( test2 );//ERROR
           

还有一点sizeof也可以作用于函数调用的,其结果是函数返回类型(不能为void)的大小,而且函数并不会实际地调用,可以参考下图。

浅说c/c++的sizeof

3.庖丁解牛,深入理解sizeof

3.1 sizeof的常量性

sizeof的计算发生在编译期间,所以它可以当做常量表达式使用,如

3.2 内置类型的sizeof

内置类型包括int,unsigned int,short,double,float 等等等。这些类型的sizeof的大小依赖于编译器的具体实现,如在32位系统,sizeof(int)大小为4字节。特别的,对于char,unsigned char和signed char来说,标准规定了它们的sizeof大小就是为1字节。

3.3 指针变量的sizeof

对于指针变量的sizeof大小同样依赖于编译器的实现,一般来说在32位系统下,指针变量的sizeof大小为4字节。

3.4 数组的sizeof

数组的sizeof大小等于数组内各个元素占用的字节数之和。如下图所示:对arr数组做sizeof操作得到的值为16字节。

浅说c/c++的sizeof

利用这个特性,我们很容易用memset函数来初始化数组了。memset函数的原型为:

void* memset(void *s,int ch,size_t n);
           

其作用就是将s中当前位置后面的 n 个字节用 ch 替换并返回 s 。 所以对于数组来说,我们很自然的就可以用 memset(arr,0,sizeof(arr));这样的形式来初始化数组了。

3.5 结构体/类的sizeof

对于结构体或类的sizeof大小,是比较容易犯错也是在面试中经常被考察的一部分。下面我们来具体分析下。

3.5.1 空类的sizeof

1)对于

class CTest{};sizeof( CTest);

为多少呢?理论上,没有数据成员的类的大小应该为0,但是实际上sizeof(CTest)的大小却为1,这是为什么呢?先了解一个概念:类的实例化,所谓类的实例化就是在内存中分配一块地址,每个实例在内存中都有独一无二的地址。同样空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。

2)对于基类和子类都是空类的情况下,子类的sizeof大小为多少呢?会是2么?看如下的代码。

浅说c/c++的sizeof

很明显,对于了继承了空类的子类sizeof大小同样为1。

3.5.2 有虚函数类的sizeof
class CTest
{
    public:
    virtual ~CTest();
};
           

sizeof(CTest)的大小会是多少呢?会是1么?看看执行的结果:

浅说c/c++的sizeof

结果是4字节,为什么呢?这是因为一般来说编译器会为包含了虚函数的类创建一个表(VTABLE),并且还秘密的在类中放置一个指针(VPTR),来指向这个表。指针变量的sizeof大小是多少呢?通过前面我们知道,在32位编译系统下是4,符合我们的预期。

3.5.3 带有静态数据成员的类
class CTest
{
    int data;
    static int value;
};
           

同样我们会好奇sizeof(CTest)的大小为多少呢?看看下面代码执行的结果。

浅说c/c++的sizeof

在类里面,静态的数据成员虽然属于这个类,但是却不影响这个类的大小。所以,CTest类的sizeof大小就是sizeof(int)的大小,为4字节。

3.5.4 考虑到内存对齐的sizeof
class CTest
{
    char ch;
    int  data;
};
           

从直观上看,sizeof(CTest)的大小为sizeof(char)+sizeof(int)的大小也就是5个字节,然而真的是么?看看如下代码执行的结果:

浅说c/c++的sizeof

为什么是8个字节呢?这就要考虑到内存对齐方式了。关于内存对齐方式我们在这里不做过多介绍,有兴趣的读者可以自行查阅别的资料。在这里我们只考虑到编译器默认(不考虑#pragma pack)的内存对齐方式,sizeof的结果请牢记以下3条原则:

1:数据成员对齐规则:结构(struct)(或联合(union))的数据成员,第一个数据成员放在offset为0的地方,以后每个数据成员存储的起始位置要从该成员大小或者成员的子成员大小(只要该成员有子成员,比如说是数组,结构体等)的整数倍开始(比如int在32位机为4字节,则要从4的整数倍地址开始存储)。

2:结构体作为成员:如果一个结构里有某些结构体成员,则结构体成员要从其内部最大元素大小的整数倍地址开始存储.(struct a里存有struct b,b里有char,int ,double等元素,那b应该从8的整数倍开始存储.)

3:收尾工作:结构体的总大小,也就是sizeof的结果,.必须是其内部最大成员的整数倍.不足的要补齐.

总结: 在这里我们考虑多种情况下sizeof的结果,当然还有一些情况没有讨论,包括但不限于:1)通过 #pragma pack改变内存对齐方式 ;2)union类型的sizeof大小;3)含位域结构体的sizeof等等。这些情况读者可以自行去查阅相关资料。

PS: 笔者学识有限,行文或对c++理解难免会有错误,若有不对处,还请各位指正。

参考资料:

http://blog.csdn.net/wzy198852/article/details/7246836

http://blog.csdn.net/zzhongcy/article/details/38361755

http://www.360doc.com/content/11/0324/15/6637130_104204413.shtml

继续阅读