为什么sizeof(x ++)不增加x?
以下是在dev c ++ windows中编译的代码:
#include <stdio.h> int main() { int x = 5; printf("%d and ", sizeof(x++)); // note 1 printf("%d\n", x); // note 2 return 0; }
执行注1后,我预计x
是6。 但是,输出是:
4 and 5
任何人都可以解释为什么在注1后x
不增加?
从C99标准 (重点是我的)
6.5.3.4/2
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是一个expression式或一个types的括号内的名称。 大小取决于操作数的types。 结果是一个整数。 如果操作数的types是可变长度数组types,则评估操作数; 否则, 操作数不计算 ,结果是一个整数常量。
sizeof
是一个编译时操作符 ,所以在编译时sizeof
和它的操作数被结果值replace。 操作数不被评估 (除非是可变长度数组); 只有结果的types很重要。
short func(short x) { // this function never gets called !! printf("%d", x); // this print never happens return x; } int main() { printf("%d", sizeof(func(3))); // all that matters to sizeof is the // return type of the function. return 0; }
输出:
2
因为我的机器上占用2个字节。
将函数的返回types更改为double
:
double func(short x) { // rest all same
会给8
作为输出。
sizeof(foo)
在编译时真的很难发现expression式的大小:
6.5.3.4:
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是一个expression式或一个types的括号内的名称。 大小取决于操作数的types。 结果是一个整数。 如果操作数的types是可变长度数组types,则评估操作数; 否则,操作数不计算,结果是一个整数常量。
简而言之:变长数组,在运行时运行。 (注意: 可变长度数组是一个特定的特性 – 不是用malloc(3)
分配的数组。)否则,只有expression式的types被计算,并且在编译时。
sizeof
是一个编译时内置操作符, 不是一个函数。 在没有括号的情况下,您可以使用它,这变得非常清楚:
(sizeof x) //this also works
注意
这个答案是从一个重复的,这解释了晚date合并。
原版的
除了可变长度数组, sizeof不会评估它的参数。 我们可以从C99标准草案部分看到这个6.5.3.4
操作符 2的大 6.5.3.4
:
sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是一个expression式或一个types的括号内的名称。 大小取决于操作数的types。 结果是一个整数。 如果操作数的types是可变长度数组types,则评估操作数; 否则,操作数不计算,结果是一个整数常量。
一个评论( 现在删除 )问是否会在运行时评估这样的事情:
sizeof( char[x++] ) ;
而事实上,这样的事情也会起作用( 见他们都活着 ):
sizeof( char[func()] ) ;
因为它们都是可变长度的数组。 虽然我看不出有太大的实际用处。
请注意,可变长度数组在C99标准部分中有介绍6.7.5.2
数组声明 6.7.5.2
第4段 :
[…]如果大小是一个整型常量expression式,并且元素types具有已知的常量大小,则数组types不是可变长度数组types; 否则,数组types是一个可变长度的数组types。
更新
在C11中,答案在VLA情况下发生变化,在某些情况下,不确定是否评估了大小expression式。 来自第6.7.6.2
节的数组声明 6.7.6.2
:
[…]如果sizeexpression式是sizeof运算符的操作数的一部分,并且更改sizeexpression式的值不会影响运算符的结果,则不指定是否计算大小expression式。
例如,在这样的情况下( 看它现场 ):
sizeof( int (*)[x++] )
由于sizeof
运算符的操作数没有被评估,所以你可以这样做:
int f(); //no definition, which means we cannot call it int main(void) { printf("%d", sizeof(f()) ); //no linker error return 0; }
在线演示: http : //ideone.com/S8e2Y
也就是说,如果仅在sizeof
使用,则不需要定义函数f
。 这种技术主要用于C ++模板元编程,即使在C ++中, sizeof
的操作数也不被计算。
为什么这个工作? 它的工作原理是因为sizeof
运算符没有对值进行操作,而是对expression式的types进行操作。 所以当你写sizeof(f())
,它会根据expression式f()
的types进行操作,而这只不过是函数f
的返回types。 返回types始终是相同的,无论函数实际执行的返回值是什么。
在C ++中,你甚至可以这样做:
struct A { A(); //no definition, which means we cannot create instance! int f(); //no definition, which means we cannot call it }; int main() { std::cout << sizeof(A().f())<< std::endl; return 0; }
然而,在sizeof
,我首先创buildA
一个实例,编写A()
,然后通过编写A().f()
调用实例的函数f
,但是不会发生这种事情。
演示: http : //ideone.com/egPMi
这里是另一个解释sizeof
其他一些有趣属性的主题:
- 大小取两个参数
编译期间不能执行。 所以++i
/ i++
不会发生。 sizeof(foo())
也不会执行这个函数,而是返回正确的types。
sizeof()
运算符只给出数据types的大小,它不会评估内部元素。