首页 > 编程知识 正文

逗号运算符和赋值运算符的优先级,c语言程序运算符sizeof

时间:2023-05-04 17:34:28 阅读:118233 作者:3180

sizeof运算符的系统总结标签: c/c

总结http://blog.csdn.net/w57w 57w 57/article/details/6626840

sizeof是C/C关键字,是用于获取对象(数据类型或数据对象)长度的运算符。 也就是说,以字节为单位消耗内存。 类型包括基本数据类型(不包括void)、用户定义的类型(结构、类)和函数类型。 数据对象是在上述类型中定义的常规变量和指针变量(包括void指针)。 虽然每个平台的大小因数据类型而异,但c标准要求所有编译平台都确保sizeof(char )为1。 有关sizeof的详细信息,可以在msdn中输入sizeof进行联系。

看到这些,你可能没什么感觉。 没关系。 详细说明sizeof的许多特性。 这些特性是sizeof是更刁难的关键字的原因。

特性

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

这个特性是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类型的指针,如属性1中所述。 这意味着编译器可以确定void类型指针占用的存储空间。 事实上是的。 目前,大多数平台上所有版本的编译器都将指针大小视为4字节。 请尝试sizeof(int* )。 sizeof (语音*; sizeof (双精度*; sizeof (人员*; 等等,它们都等于4! 为什么呢? 理由很简单。 其实指针也是变量。 但是,该变量是特殊的,是存储其他变量地址的变量。 此外,当前32位计算机平台上的段的地址范围都为4GB,最小寻址单位为字节,4GB为232字节,因此这些内存的地址编码后只需要32位,而32位因此,如果对所有类型的指针变量执行sizeof运算,其结果为4。

特性3:sizeof可以静态地求出分配存储器的数组的长度

Int a[10]; intn=sizeof(a; 如果sizeof(int )为4,则n=10*4=40; 特别注意: char ch[]='abc '; Sizeof(ch; 请注意,结果为4,字符串数组末尾有’ 0’! 通常,数组中包含的元素数可以使用sizeof计算,如intn=sizeof(a ) sizeof (a [0] )。

【需要注意】在函数的形状参数组中使用sizeof时。 例如,假设有以下函数:

voidfun(intArray[10] ) intn=sizeof (array ); )在fun内,你觉得n的值是多少? 如果你回答40,很遗憾不是。 这里n是4。 实际上,无论是参数为int的类型数组、float类型数组、其他用户定义类型的数组还是数组包含多少元素,其中的n都是4。 为什么呢? 也许你可以问为什么转换为原因是在函数参数传递时,数组被转化成指针了指针,简单地说,直接传递整个数组必然涉及数组元素的复制(从实参到形参的复制),如果数组非常大,函数的执行效率非常高要只传递数组的地址(即指针),只需复制4字节。

特性4:sizeof无法求出动态分配的内存大小!

假设有以下句子。 int *a=new int[10]; intn=sizeof(a; n的值是多少? 40吗? 答案是否定的! 其实n是4。 a是指针,所以在特性2中进行了叙述。 在32位平台上,所有指针的大小都为4字节。 请注意,这里的a与特性3的a不同。 特性3中的a是数组名称,其中的a是指针。 很多人认为数组名称是指针,其实不然。 两者有很多区别。 特性3和特性4表明,数组和指针有多种关系,这些关系也是引起程序潜在错误的主要因素。

特性3示出了特性4,其中sizeof可以确定静态分配的阵列的大小

说明sizeof不能求的动态分配的内存的大小。那么问题来了,sizeof是在什么时候进行求值运算的?有人认为sizeof是编译时进行求值的,并给出理由:语句 int array[sizeof(int)*10]; 能编译通过,而很多书上都说过数组大小是编译时就确定下来的,既然前面的语句能编译通过,所以认为sizeof是编译时进行求值的。经过进一步测试我发现这个结论有些武断!至少是有些不严谨!因为在实现了c99标准的编译器(如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[10] = {1,2,3,4,5,6,7,8,9,10};int arrayB[10] = {11,12,13,14,15,16,17,18,19,20};

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

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

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

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

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

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

char ch = 1;int num = 1;int n1 = sizeof(ch+num);int n2 = sizeof(ch = ch+num);

  假设char占用1byte,int占用4byte,那么执行上面的程序之后,n1,n2,ch的值是多少呢?我相信有不少人会认为n1与n2相等,也有不少人认为ch等于2,事实这些人都错了。事实上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返回的是表达式计算结果的类型大小,而不是表达式中占用最大内存的变量的类型大小!

  对于 n2=sizeof(ch=ch+num); 乍一看该程序貌似实现了让ch加上num并赋值给ch的功能,事实并非如此!由于sizeof只关心类型大小,所以它自然不应该对表达式求值,否则有画蛇添足之嫌了。正是因为这点,这里告诫各位,尽量不要在sizeof中直接对表达式求大小,以免出现错误,你可以将 sizeof(ch = ch+num); 改写成 ch = ch +num; sizeof(ch); 虽然多了一条语句,看似冗余了,其实好处多多:首先更加清晰明了,其次不会出现ch等于1这样的错误(假设程序的逻辑本身就是要执行ch = ch +num;)。

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

假设有如下函数(是一个写得很不好的函数,但是能很好的说明需要阐述的问题):

int fun(int& num,const int& inc){ float div = 2.0; double ret =0; num = num+inc; ret = num/div; return ret;}

那么语句:

int a = 3;int b = 5;cout<<sizeof(fun(a,b))<<endl;cout<<a<<endl;

  输出多少呢?不同的人会给出不同的答案,我将对sizeof(fun(a,b))的值和a的值分别进行讨论:

  首先sizeof(fun(a,b))的值:其正确是4,因为用sizeof求函数调用的大小时,它得到的是函数返回类型的大小,而fun(a,b)的返回类型是int,sizeof(int)等于4。很多人把函数的返回类型和返回值的类型弄混淆了,认为sizeof(fun(a,b))的值是8,因为函数返回值是ret,而ret被定义成double,sizeof(doube)等于8。注意,虽然函数返回值类型是double,但是在函数返回时,将该值进行了类型转换(这里的转换不安全)。也有人错误的认为sizeof(fun(a,b))的值是12,它们的理由是:fun内部定义了两个局部变量,一个是float一个是double,而 sizeof(float) + sizeof(doube) = 4+8 = 12 。这样的答案看似很合理,其实他们是错误地认为这里的sizeof是在求函数内部的变量的大小了。这当然是错误的。

  接下来看a的值:其正确答案是3!还记得特性6吗?这里很类似,sizeof的操作对象是函数调用时,它不执行函数体!为此,建议大家不要把函数体放在sizeof后面的括号里,这样容易让人误以为函数执行了,其实它根本没执行。

  既然对函数条用使用sizeof得到的是函数返回类型的大小,那么很自然能得出这样的结论:不能对返回类型为void的函数使用sizeof求其大小!原因请参考特性1。同理,对返回类型是任何类型的指针的函数调用使用sizeof求得的大小都为4,原因请参考特性2。

  最后我们来看看这样的语句: cout<<sizeof(fun); 其答案是多少呢?其实它得不到答案,原因是编译就通不过!最开始,我以为能输出答案4,因为我认为fun是函数名,而我知道函数名就是函数的地址,地址就是指针,于是我认为sizeof(fun)其实就是对一个指针(函数名是指针常量?)求大小,根据特性2,任何指针的大小都是4。可是验证时,编译器根本不让通过!这个是为什么呢?或许是标准有规定吧。暂时没有准确的答案。

特性8:sizeof求得的结构体(及其对象)的大小并不等于各个数据成员对象的大小之和!
给出相关规则,具体分析见sizeof求解结构体大小的问题

(1)结构体变量中成员的偏移量必须是成员大小的整数倍(0被认为是任何数的整数倍)
(2)结构体大小必须是所有成员大小的整数倍,也即所有成员大小的公倍数。

  需要提醒的是,在进行设计时,最好仔细安排结构体中各个成员的顺序,因为你已经看到了上面的结构体B与结构体A包含的成员相同,只不过顺序略有差异,最终就导致了B比A多消耗了50%的空间,假如在工程中需要定义该结构体的数组,多消耗的空降将是巨大的。

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

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

Struct A{ Bool b:1; char ch1:4; char ch2:4;}item;

  其中b,ch1,ch2都是位域成员。该结构体的试图让bool类型的变量b只占用1个bit,让ch1和ch2分别只占用4个bit,以此来达到对内存精打细算的功能(事实上使用位域对内存精打细算有时候能成功,有时候却未必)。另外需要特别注意的是:c语言规定位域只能用于int,signed int或者unsigned int类型,C++又补充了char和long类型!你不能这样使用位域:float:9;这是不能通过编译的。并且位域变量不能在函数或者全局区定义,只能在结构体,自定义类,联合(union)中使用!

  基于上面的结构体,语句sizeof(item.b)和sizeof(item.ch1)等对位域成员求大小的语句均不能通过编译。其原因是:sizeof以byte为单位返回操作数的大小!

  那么,sizeof(A)能否通过编译呢?如何能,其结果又是多少呢?这是两给非常好的问题,事实上我之前没有看到任何关于这方面的论述(可能是我看的资料不足),我正是在看到sizeof(item.b)不能通过编译时想到了这两个问题,然后通过验证得出了后面的结论:对包含位域的结构体是可以使用sizeof求其大小的,但其求值规则比较复杂,不仅涉及到成员对齐,还与具体编译环境有关!在这里你只需要知道可以对包含位域的结构体使用sizeof求其大小就可以了。

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。