sizeof()使用小结

特性0:sizeof是运算符,不是函数

  sizeof最基本特性,后面的很多特性都是受到这个特性的影响,正因为sizeof不是函数,因此不把它所要求得长度的对象叫做参数,习惯上叫做操作数。

特性1:sizeof不能求得void类型的长度

  不能用sizeof(void),这将导致编译错误:illegalsizeof operand。因为无法声明void类型的变量,可以试试void a; 编译器会报错:illegal use of type 'void'。声明变量的一个重要作用就是告诉编译器该变量需要多少存储空间。但void是“空类型”,你可以理解成不知道存储空间大小的类型。既然编译器无法确定void类型的变量的存储大小,那么它自然不让你声明这样的变量。当然了,声明void类型的指针是可以的!这就是特性2的内容。

特性2:sizeof能求得void类型的指针的长度

  编译器可以确定void类型的指针所占用的存储空间,大小是4byte,如sizeof(int*);sizeof(void*);sizeof(double*);sizeof(Person*);等等。指针也是变量,只不过这个变量很特殊,它是存放其他变量的地址的变量。又由于目前32位计算机平台上的程序段的寻址范围都是4GB,寻址的最小单元是byte,4GB等于232Byte,这么多的内存其地址如果编码呢,只需要用32个bit就行了,而32bit = 32/8 = 4byte,也就是说只需要4byte就能存储这些内存的地址了。因此对任何类型的指针变量进行sizeof运算其结果就是4!

特性3:sizeof能求得静态分配内存的数组的长度!

  int a[10]; int n = sizeof(a); 假设sizeof(int)等于4,则n= 10*4=40;特别要注意:char ch[]=”abc”;sizeof(ch);结果为4,注意字符串数组末尾有’\0’!通常我们可以利用sizeof来计算数组中包含的元素个数,其做法是:int n = sizeof(a)/sizeof(a[0]); 非常需要注意的是对函数的形参数组使用sizeof的情况。举例来说,假设有如下的函数:

void fun(int array[])
{
int n = sizeof(array);
}

  这里n等于4,事实上不管形参是int的型数组,还是float型数组,或者其他任何用户自定义类型的数组,也不管数组包含多少个元素,这里的n都是4!原因是在函数参数传递时,数组被转化成指针了,原因:假如直接传递整个数组的话,那么必然涉及到数组元素的拷贝(实参到形参的拷贝),当数组非常大时,这会导致函数执行效率极低!而只传递数组的地址(即指针)那么只需要拷贝4byte。

特性4:sizeof不能求得动态分配的内存的大小!

  假如有如下语句:int*a = new int[10]; int n = sizeof(a); 那么n的值是多少呢?是40吗?答案是否定的!其实n等于4,因为a是指针,在特性2中讲过:在32位平台下,所有指针的大小都是4byte!很多人都认为数组名就是指针,其实不然,二者有很多区别的,可参看《c专家编程》。

  有人认为sizeof是编译时进行求值的,并给出理由:语句 int array[sizeof(int)*10]; 能编译通过。但在编译器(如DEV C++)中定义动态数组,即:语句:int num; cin>>num;  int arrary[num];是对的(注意在vc6.0中是错的)。同样在DEV C++中对刚才的array利用语句int n=sizeof(array);cout<<n<<endl来求大小,结果编译通过,运行时输入num的值10之后,输出n等于40!在这里很明显num的值是运行时才输入的,因此sizeof不可能在编译时就求得array的大小!这样一来sizeof又变成是运行时求值的了。

  那么到底sizeof是编译时求值还是运行时求值呢?最开初c标准规定sizeof只能编译时求值,后来c99又补充规定sizeof可以运行时求值。但值得注意的是,即便是在实现了c99标准的DEV C++中仍然不能用sizeof求得动态分配的内存的大小!

特性5:sizeof不能对不完整的数组求长度!

  在阐述该特性之前,我们假设有两个源文件:file1.cpp和file2.cpp,其中file1.cpp中有如下的定义:

int arrayA[] = {,,,,,,,,,};
int arrayB[] = {,,,,,,,,,};

  file2.cpp包含如下几个语句:

extern arrayA[];
extern arrayB[];
cout<<sizeof(arrayA)<<endl; //编译出错!!
cout<<sizeof(arrayB)<<endl; //

  原因是sizeof(arrayA)试图求不完整数组的大小。这里的不完整的数组是指数组大小没有确定的数组!sizeof运算符的功能就是求某种对象的大小,然而声明:extern int arrayA[]只是告诉编译器arrayA是一个整型数组,但是并没告诉编译器它包含多少个元素,因此对file2.cpp中的sizeof来说它无法求出arrayA的大小,所以编译器干脆不让你通过编译。

  那为什么sizeof(arrayB)又可以得到arraryB的大小呢?关键就在于在file2.cpp中其声明时使用externint arrayB[10]明确地告诉编译器arrayB是一个包含10个元素的整型数组,因此大小是确定的。

特性6:当表达式作为sizeof的操作数时,它返回表达式的计算结果的类型大小,但是它不对表达式求值!

  为了说明这个问题,我们来看如下的程序语句:

char ch = ;
int num = ;
int n1 = sizeof(ch + num); //
int n2 = sizeof(ch = ch+num); //1, 其中ch = 1

  执行上面的程序之后,n1等于4,n2等于1,ch等于1。由于默认类型转换的原因,表达式ch+num的计算结果的类型是int,因此n1的值为4!而表达式ch=ch+num;的结果的类型是char,虽然在计算ch+num时,结果为int,但是当把结果赋值给ch时又进行了类型转换,因此表达式的最终类型还是char,所以n2等于1。n1, n2的值分别为4和1,其原因正是因为sizeof返回的是表达式计算结果的类型大小,而不是表达式中占用最大内存的变量的类型大小!

特性7:sizeof可以对函数调用求大小,并且求得的大小等于返回类型的大小,但是不执行函数体!

  假设有如下函数:

int fun(int& num,const int& inc)
{
float div = 2.0;
double ret =;
num = num+inc;
ret = num/div;
return ret;
} int a = ;
int b = ;
cout << sizeof(fun(a,b)) << endl; //4,操作对象是函数调用时,不执行函数体
cout << a << endl; //

  首先sizeof(fun(a,b))的值:其正确是4,因为用sizeof求函数调用的大小时,它得到的是函数返回类型的大小,而fun(a,b)的返回类型是int,sizeof(int)等于4。函数的返回类型和返回值的类型是不一样的。来看语句:cout<<sizeof(fun);其答案是多少呢?其实它得不到答案,原因是编译就通不过!原因待补充。

特性8:sizeof求得的结构体(及其对象)的大小并不等于各个数据成员对象的大小之和!

  结构体的大小跟结构体成员对齐有密切关系,而并非简单地等于各个成员的大小之和!比如对如下结构体两个结构体A、B使用sizeof的结果分别是:16,24。可以看出sizeof(B)并不等于sizeof(int)+sizeof(double)+sizeof(int)=16。

struct A{

int num1;

int num2;

double num3;

};

struct B{

int num1;

double num3;

int num2;

};

其规则如下:

  1.结构体的大小等于结构体内最大成员大小的整数倍

  2.结构体内的成员的首地址相对于结构体首地址的偏移量是其类型大小的整数倍,如double成员相对于结构体的首地址的地址偏移量应该是8的倍数。

  3.为了满足规则1和2编译器会在结构体成员之后进行字节填充!

  在进行设计时,要安排好结构体中各个成员的顺序,顺序略有差异,可能导致B比A多消耗了50%的空间!

特性9:sizeof不能用于求结构体的位域成员的大小,但是可以求得包含位域成员的结构体的大小!

  首先解释一下什么是位域:类型的大小都是以字节(byte)为基本单位的,比如sizeof(char)为1byte,sizeof(int)为4byte等。但bool类型只取值true和false,按理所只用1bit(即1/8byte)就够了,但事实上sizeof(bool)等于1。因此可以认为bool变量浪费了87.5%(7/8)的存储空间!这在某些存储空间有限的设备(比如嵌入式设备)上是不合适的,为此需要提供一种能对变量的存储空间精打细算的机制,这就是位域。简单来说,在结构体的成员变量后面跟上的一个冒号 + 一个整数,就代表位域,请看如下的结构体:

struct A
{
Bool b:;
char ch1:;
char ch2:;
}item;

  该结构体试图让bool类型的变量b只占用1个bit,让ch1和ch2分别只占用4个bit,以此来达到对内存精打细算的功能。c语言规定位域只能用于int,signed int或者unsigned int类型,C++又补充了char和long类型!你不能这样使用位域:floatf:8;这是不能通过编译的。并且位域变量不能在函数或者全局区定义,只能在结构体,自定义类,联合(union)中使用!

  基于上面的结构体,语句sizeof(item.b)和sizeof(item.ch1)等对位域成员求大小的语句均不能通过编译。其原因能再本篇的概论中找到:sizeof以byte为单位返回操作数的大小!那么sizeof(A)能否通过编译呢?对包含位域的结构体是可以使用sizeof求其大小的,但其求值规则比较复杂,不仅涉及到成员对齐,还与具体编译环境有关!在这里你只需要知道可以对包含位域的结构体使用sizeof求其大小。

参考:http://blog.csdn.net/w57w57w57/article/details/6626840

版权:w57w57w57

c++ --> sizeof()使用小结的更多相关文章

  1. Sizeof运算符小结

    以下内容援引自<C Primer Plus>中文版第五版Page95 Sizeof运算符以字节为单位返回其操作数的大小.(在C中,1个字节被定义为char类型所占用空间的大小.在过去,1个 ...

  2. C 语言编程习惯总结

    笔者能力有限,如果文中出现错误的地方,还请各位朋友能够给我指出来,我将不胜感激,谢谢~ 引言 编程习惯的培养需要的是一个长期的过程,需要不断地总结,积累,并且我们需要从意识上认识其重要性,一个良好的编 ...

  3. sizeof和strlen小结

    sizeof和strlen小结 写在前面 之所以要总结一下sizeof和strlen的用法和区别,是因为这些知识可以帮助我们更加深入的理解各种数据结构在内存中的占用情况,也许表面上看好像没有多大用处, ...

  4. 内存对齐 和 sizeof小结

    数据对齐(内存对齐)指该数据所在的地址必须是该数据长度的整数倍.X86CPU能直接访问对齐的数据,当它试图访问未对齐的数据时,会在内部进行一系列的调整,降低运行速度.数据对齐一般出现在结构体和类中,在 ...

  5. c++面试常用知识(sizeof计算类的大小,虚拟继承,重载,隐藏,覆盖)

    一. sizeof计算结构体 注:本机机器字长为64位 1.最普通的类和普通的继承 #include<iostream> using namespace std; class Parent ...

  6. 函数fgets和fputs、fread和fwrite、fscanf和fprintf用法小结 (转)

    函数fgets和fputs.fread和fwrite.fscanf和fprintf用法小结 字符串读写函数fgets和fputs 一.读字符串函数fgets函数的功能是从指定的文件中读一个字符串到字符 ...

  7. sizeof既是关键字,又是运算符(操作符),但不是函数!

    sizeof是关键字吗 sizeof是关键字,这一点毋庸置疑.你不能将sizeof定义为任何标识符.查看C语言标准文档里的说明: sizeof是运算符(操作符)吗 C语言中,sizeof是运算符(操作 ...

  8. 高通平台 lcd driver 调试小结

    一.概述 1.1 简介 本文档主要包括LCD模块的驱动流程分析.Framebuffer相关知识.Gralloc等相关内容,以及LCD调试的一些经验和相关bug的分析和讲解. 1.2  开发环境 And ...

  9. [数据结构]KMP小结

    KMP小结   By Wine93 2013.9 1.学习链接: http://www.matrix67.com/blog/archives/115 2.个人小结 1.KMP在字符串中匹配中起着巨大作 ...

随机推荐

  1. hi3531的时钟系统

    时钟管理模块对芯片时钟输入.时钟生成和控制进行统一的管理,包括: 时钟管理模块有以下两部分输入:

  2. javascript parseint

  3. Caused by: java.lang.ClassNotFoundException: org.hibernate.annotations.common.reflection.MetadataPro

    1.错误描述 信息: MLog clients using java 1.4+ standard logging. 2014-7-12 19:29:20 com.mchange.v2.c3p0.C3P ...

  4. Linux下挂载新硬盘方法

     Linux的硬盘识别在/dev/下建立相应的设备文件.如 sda 表示第一块SCSI硬盘 hda 表示第一块IDE硬盘(即连接在第一个IDE接口的Master口上) scd0 表示第一个USB光 ...

  5. 过滤文件代码 python

    import os import cv2 import shutil # store all file in directory global totalFileList totalFileList ...

  6. Spring AOP介绍

    1.介绍 AOP(面向切面编程)对OOP(面向对象编程)是一种补充,它提供了另一种程序结构的思路.OOP的模块单元是class,而AOP的模块单元是aspect.Spring中一个关键的组件是AOP框 ...

  7. Keras常见问题及解答

    Keras官方中文版文档 如何引用 Keras? 如何在 GPU 上运行 Keras? 如何在多 GPU 上运行 Keras 模型? "sample", "batch&q ...

  8. SpringBoot集成Shiro并用MongoDB做Session存储

    之前项目鉴权一直使用的Shiro,那是在Spring MVC里面使用的比较多,而且都是用XML来配置,用Shiro来做权限控制相对比较简单而且成熟,而且我一直都把Shiro的session放在mong ...

  9. 【BZOJ4825】【HNOI2017】单旋(Link-Cut Tree)

    [BZOJ4825][HNOI2017]单旋(Link-Cut Tree) 题面 题面太长,懒得粘过来 题解 既然题目让你写Spaly 那就肯定不是正解 这道题目,让你求的是最大/最小值的深度 如果有 ...

  10. [CF908D]New Year and Arbitrary Arrangement

    题面在这里 题意 给定三个数\(k,pa,pb\),每次有\(\frac{pa}{pa+pb}\)的概率往后面添加一个'\(a\)',每次有\(\frac{pb}{pa+pb}\)的概率往后面添加一个 ...