为什么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 

任何人都可以解释为什么在注1x不增加?

从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的大小,它不会评估内部元素。