sizeof总结

来源:互联网 发布:大数据决策支持系统 编辑:程序博客网 时间:2024/05/18 20:09

一 定义

sizeofC/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。

MSDN上的解释为:

The sizeof keyword gives the amount of storage, in bytes, associated with avariable or a type(including aggregate types). This keyword returns a value of type size_t.

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

typedef unsigned int size_t;

 

世上编译器林林总总,但作为一个规范,它们都会保证charsigned charunsigned

charsizeof值为1,毕竟char是我们编程能用的最小数据类型

 

语法

sizeof有三种语法形式,如下:

sizeof(object);//sizeof(对象);

sizeof(type_name);//sizeof(类型);

sizeofobject;//sizeof对象; 

所以,

inti;

sizeof(i);//ok

sizeofi;//ok

sizeof(int);//ok

sizeofint;//error

 

既然写法3可以用写法1代替,为求形式统一以及减少我们大脑的负担,第3种写法,忘掉它吧!实际上,sizeof计算对象的大小也是转换成对对象类型的计算,也就是说,同种类型的不同对象其sizeof值都是一致的。这里,对象可以进一步延伸至表达式,即sizeof可以对一个表达式求值,编译器根据表达式的最终结果类型来确定大小,一般不会对表达式进行计算。如:

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

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

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

二 基本数据类型的sizeof

cout<<sizeof(char)<<endl;          结果是1cout<<sizeof(int)<<endl;           结果是4cout<<sizeof(unsigned int)<<endl;   结果是4 cout<<sizeof(long int)<<endl;       结果是4cout<<sizeof(short int)<<endl;       结果是2cout<<sizeof(float)<<endl;          结果是4cout<<sizeof(double)<<endl;        结果是8 

三 数组的sizeof

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

char a1[] = "abc";int a2[3];sizeof( a1 ); // 结果为4,字符 末尾还存在一个NULL终止符sizeof( a2 ); // 结果为3*4=12(依赖于int)

写到这里,提一问,下面的c3c4值应该是多少呢

void foo3(char a3[3]){int c3 = sizeof( a3 ); // c3 == 4}void foo4(char a4[]){int c4 = sizeof( a4 ); // c4 == 4}

也许当你试图回答c4的值时已经意识到c3答错了,是的,c3!=3。这里函数参数a3已不再是数组类型,而是蜕变成指针,相当于char* a3,为什么仔细想想就不难明白,我们调用函数foo1时,程序会在栈上分配一个大小为3的数组吗不会!数组是“传址”的,调用者只需将实参的地址传递过去,所以a3自然为指针类型(char*),c3的值也就为4 

四 结构体的sizeof 

struct MyStruct{           double dda1;           char dda;           int type};//结果为16 

为上面的结构分配空间的时候,VC根据成员变量出现的顺序和对齐方式,先为第一个成员dda1分配空间,其起始地址跟结构的起始地址相同(刚好偏移量0刚好为sizeof(double)的倍数),该成员变量占用sizeof(double)=8个字节

接下来为第二个成员dda分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为8,是sizeof(char)的倍数,所以把dda存放在偏移量为8的地方满足对齐方式,该成员变量占用sizeof(char)=1个字节;接下来为第三个成员type分配空间,这时下一个可以分配的地址对于结构的起始地址的偏移量为9,不是sizeof(int)=4的倍数,为了满足对齐方式对偏移量的约束问题,VC自动填充3个字节(这三个字节没有放什么东西),这时下一个可以分配的地址对于结构的起始地址的偏移量为12,刚好是sizeof(int)=4的倍数,所以把type存放在偏移量为12的地方,该成员变量占用sizeof(int)=4个字节;这时整个结构的成员变量已经都分配了空间,总的占用的空间大小为:8+1+3+4=16,刚好为结构的字节边界数(即结构中占用最大空间的类型所占用的字节数sizeof(double)=8)的倍数,所以没有空缺的字节需要填充。所以整个结构的大小为:sizeof(MyStruct)=8+1+3+4=16,其中有3个字节是VC自动填充的,没有放任何有意义的东西。 

五 含位域结构体的sizeof

示例1

struct BF1

{

char f1 : 3;

char f2 : 4;

char f3 : 5;

};

其内存布局为:

|_f1__|__f2__|_|____f3___|____|

|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|_|

0 3 7 8 1316

位域类型为char,第1个字节仅能容纳下f1f2,所以f2被压缩到第1个字节中,而f3只能从下一个字节开始。因此sizeof(BF1)的结果为2 

六 含有联合体的结构体的sizeof 

struct s1{           char *ptr,ch;                   //有指针变成4+4           union A            //后面跟了A定义了一个类型,不占内存,而后面不跟A,是声明了结构体的一个成员,占内存,          {              short a,b;              unsigned int c:2, d:1;           };           struct s1* next;                //指针占4};//这样是8+4=12个字节struct s1{           char *ptr,ch;                                     union                                            //联合体是结构体的成员,占内存,并且最大类型是unsigned int,占4          {               short a,b;               unsigned int c:2, d:1;           };           struct s1* next;                        };//这样是8+4+4=16个字节 

七 结构体体含有结构体的sizeof 

struct S1

    {

     char c;

     int i;

    };

struct S3

    {

     char c1;

     S1 s;

     char c2;

    };

cout<<sizeof(S3);      //S3=16

S1的最宽简单成员的类型为intS3在考虑最宽简单类型成员时是将S1“打散”看的,

所以S3的最宽简单类型为int,这样,通过S3定义的变量,其存储空间首地址需要被4

除,整个sizeof(S3)的值也应该被4整除。

c1的偏移量为0s的偏移量呢这时s是一个整体,它作为结构体变量也满足前面三个

准则,所以其大小为8,偏移量为4c1s之间便需要3个填充字节,而c2s之间就不需

要了,所以c2的偏移量为12,算上c2的大小为1313是不能被4整除的,这样末尾还得补

3个填充字节。最后得到sizeof(S3)的值为16 

八 带有#pragma packsizeof

它是用来调整结构体对齐方式的,不同编译器名称和用法略有不同,VC6中通过#pragma pack实现,也可以直接修改/Zp编译开关。#pragma pack的基本用法为:#pragma pack( n )n为字节对齐

数,其取值为124816,默认是8,如果这个值比结构体成员的sizeof值小,那么该成员的偏移量应该以此值为准,即是说,结构体成员的偏移量应该取二者的最小值,

 再看示例:

#pragma pack(push) // 将当前pack设置压栈保存#pragma pack(2)// 必须在结构体定义之前使用struct S1{char c;int i;};struct S3{char c1;S1 s;char c2};#pragma pack(pop) // 恢复先前的pack设置

计算sizeof(S1)时,min(2, sizeof(i))的值为2,所以i的偏移量为2,加上sizeof(i)

等于6,能够被2整除,所以整个S1的大小为6

同样,对于sizeof(S3)s的偏移量为2c2的偏移量为8,加上sizeof(c2)等于9,不能

2整除,添加一个填充字节,所以sizeof(S3)等于10 

九 空结构体的sizeof

struct S5 { };

sizeof( S5 ); // 结果为1

十 类的sizeof

类的sizeof值等于类中成员变量所占用的内存字节数。如:

****************************************************************class A{public:          int b;          float c;          char d;};int main(void){A object;cout << "sizeof(object) is " << sizeof(object) << endl;return 0 ;}************************************************************输出结果为12(我的机器上sizeof(float)值为4,字节对其前面已经讲过)。不过需要注意的是,如果类中存在静态成员变量,结果又会是什么样子呢?************************************************************class A{public:          static int a;          int b;          float c;          char d;}; int main(){A object;cout << "sizeof(object) is " << sizeof(object) << endl;return 0 ;}************************************************************

16?不对。结果仍然是12.

因为在程序编译期间,就已经为static变量在静态存储区域分配了内存空间,并且这块内存在程序的整个运行期间都存在。

而每次声明了类A的一个对象的时候,为该对象在堆上,根据对象的大小分配内存。

如果类A中包含成员函数,那么又会是怎样的情况呢?看下面的例子

************************************************************class A{public:          static int a;          int b;          float c;          char d;          int add(int x,int y)          {            return x+y;          }}; int main(){A object;cout << "sizeof(object) is " << sizeof(object) << endl;b = object.add(3,4);cout << "sizeof(object) is " << sizeof(object) << endl;return 0 ;} ************************************************************ 

结果仍为12。  

因为只有非静态类成员变量在新生成一个object的时候才需要自己的副本。

所以每个非静态成员变量在生成新object需要内存,而function是不需要的。 

参考:

1.百度百科

2.http://blog.csdn.net/jollyhope/article/details/1895357

0 0
原创粉丝点击