C++中sizeof用法总结

来源:互联网 发布:天天向上网络女神 编辑:程序博客网 时间:2024/06/05 00:50

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.

其返回值类型为size_t,在头文件stddef.h中定义。这是一个依赖于编译系统的值,一般定义为:typedef unsigned int size_t;

世上编译器林林总总,但作为一个规范,它们都会保证char、signed char和unsigned char的sizeof值为1,毕竟char是我们编程能用的最小数据类型。



2. sizeof用法


(1)基本类型

char:1short:2 int:4long:8 double:8float:4

(不同机器不一样)

sizeof(2);// 2的类型为int,所以等价于 sizeof( int ); 

sizeof( 2 +3.14); // 3.14的类型为double,2也会被提升成double类型,所以等价于 sizeof( double );


(2)函数调用

sizeof也可以对一个函数调用求值(不是函数!!!),其结果是函数返回类型的大小,函数并不会被调用。


(3)指针

看机器,32位为4,64位为8。


(4)数组

数组的sizeof值等于数组所占用的内存字节数

char a1[] = "abc";   

 sizeof( a1 );// 结果为4,字符末尾还存在一个NULL终止符

 int a2[3];       

sizeof( a2 ); // 结果为3*4=12(依赖于int)

注意:函数参数a3已不再是数组类型,而是蜕变成指针!


(4)union

结构体在内存组织上是顺序式的,联合体则是重叠式,各成员共享一段内存,所以整个联合体的sizeof也就是每个成员sizeof的最大值。

结构体的成员也可以是复合类型,这里,复合类型成员是被作为整体考虑的。

union U    {        int i;        char c;   };//sizeof (U) == 4


(5)struct

不用说,最烦人的部分就是struct了,因为涉及字节对齐。


为什么需要字节对齐?

这样有助于加快计算机的取数速度,否则就得多花指令周期了。为此,编译器默认会对结构体进行处理(实际上其它地方的数据变量也是如此),让宽度为2的基本数据类型(short等)都位于能被2整除的地址上,让宽度为4的基本数据类型(int等)都位于能被4整除的地址上,以此类推。这样,两个数中间就可能需要加入填充字节,所以整个结构体的sizeof值就增长了。


字节对齐的细节和编译器实现相关,但一般而言,满足三个准则

1)结构体变量的首地址能够被其最宽基本类型成员的大小所整除;

2)结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal padding);

3)结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在最末一个成员之后加上填充字节(trailing padding)。

需要说明的是,1)和2)描述的就是前面所说,结构体成员的地址(由首地址和偏移地址决定)为其大小的整数倍。


常见例子:

1)struct S1    {  char c;        int i;   };

对于准则1),编译器会将这个结构体的首地址位于int,也就是4的整数倍上,然后对于第一个成员char,占用1个字节,对于第二个成员int,根据准则2),偏移量应该为4,所以在char和int成员之间填充3个字节(0xCC)。所以总共占用8个字节,准则3)也实现了

2)struct S2   {  int i;     char c;  };

同理,准则1)由编译器分配内存地址实现,然后准则2)此处无用,自动实现了。因为准则3),所以在char后面填充3个字节(0xCC)。

3)struct S3    {   char c1;      S1 s;       char c2;    };

S1的最宽简单成员的类型为int,S3在考虑最宽简单类型成员时是将S1“打散”看的,所以S3的最宽简单类型为int,通过S3定义的变量,其存储空间首地址需要被4整除,整个sizeof(S3)的值也应该被4整除。

c1的偏移量为0,s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个准则,所以其大小为8,偏移量为4(int的整数倍),c1与s之间便需要3个填充字节,而c2与s之间就不需要了,所以c2的偏移量为12,算上c2的大小为13,13是不能被4整除的,这样末尾还得补上3个填充字节。最后得到sizeof(S3)的值为16。



3. sizeof和strlen区别

(1)sizeof操作符的结果类型是size_t,它在头文件中typedef为unsigned int类型。该类型保证能容纳实现所建立的最大对象的字节大小。

(2)sizeof是运算符,strlen是函数。

(3)strlen(char*)函数求的是字符串的实际长度,它求得方法是从开始到遇到第一个'\0';如果你只定义没有给它赋初值,这个结果是不定的,它会从aa首地址一直找下去,直到遇到'\0'停止。(不包含'\0');sizeof()函数返回的是变量声明后所占的内存数,不是实际长度。

(4)sizeof可以用类型做参数,strlen只能用char*做参数,且必须是以''\0''结尾的。

(5)数组做sizeof的参数不退化,传递给strlen就退化为指针了。

(6)大部分编译程序在编译的时候就把sizeof计算过了是类型或是变量的长度这就是sizeof(x)可以用来定义数组维数的原因。strlen的结果要在运行的时候才能计算出来,是用来计算字符串的长度,不是类型占内存的大小。

(7)sizeof 操作符不能返回被动态分派的数组或外部数组的尺寸

(8)strlen只能用char*做参数,且必须是以''\0''结尾的,而sizeof可用类型做参数,还可用函数做参数



关键点:

其实理解 sizeof 只需要抓住一个要点:栈

程序存储分布有三个区域:栈、静态和动态(堆)。能够从代码直接操作的对象,包括任何类型的变量、指针,都是在栈上的;动态和静态存储区是靠栈上的所有指针间接操作的。

sizeof 操作符,计算的是对象在栈上的投影体积;记住这个就很多东西都很清楚了。



需要说明的是:

sizeof的计算发生在编译时刻,所以可以当作常量表达式来使用(C99标准规定sizeof也可以在运行时刻进行计算)

C99标准规定,函数、不能确定类型的表达式以及位域(bit-field)成员不能被计算sizeof值

编译器的pack指令用来调整结构体对齐方式的,不同编译器名称和用法略有不同


0 0