为什么sizeof(x ++)不能增加x?

这是在dev c ++ windows中编译的代码:

#include  int main() { int x = 5; printf("%d and ", sizeof(x++)); // note 1 printf("%d\n", x); // note 2 return 0; } 

我希望在执行注释1x为6。 但是,输出是:

 4 and 5 

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

从C99标准 (重点是我的)

6.5.3.4/2

sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。 大小由操作数的类型确定。 结果是整数。 如果操作数的类型是可变长度数组类型,则计算操作数; 否则, 不评估操作数 ,结果是整数常量。

sizeof是一个编译 sizeof 算符 ,因此在编译时sizeof及其操作数将被结果值替换。 根本不评估操作数(除非是可变长度数组); 只有结果的类型才重要。

 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个字节。

将函数的返回类型更改为double

 double func(short x) { // rest all same 

将输出8作为输出。

sizeof(foo)在编译时很难发现表达式的大小:

6.5.3.4:

sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。 大小由操作数的类型确定。 结果是整数。 如果操作数的类型是可变长度数组类型,则计算操作数; 否则,不评估操作数,结果是整数常量。

简而言之:可变长度数组,在运行时运行。 (注意: 可变长度数组是一个特定的特性 – 不是用malloc(3)分配的数组。)否则,只计算表达式的类型 ,并在编译时计算。

sizeof是一个编译时内置运算符, 不是函数。 在没有括号的情况下可以使用它变得非常清楚:

 (sizeof x) //this also works 

注意

这个答案是从一个副本合并而来,这解释了迟到的日期。

原版的

除了可变长度数组, sizeof不会评估其参数。 我们可以从草案C99标准第6.5.3.4节中看到这6.5.3.4 。运营商2段的6.5.3.4说:

sizeof运算符产生其操作数的大小(以字节为单位),该操作数可以是表达式或类型的带括号的名称。 大小由操作数的类型确定。 结果是整数。 如果操作数的类型是可变长度数组类型,则计算操作数; 否则,不评估操作数,结果是整数常量。

评论( 现已删除 )询问是否会在运行时评估此类内容:

 sizeof( char[x++] ) ; 

事实上,这样的事情也会起作用( 看到它们都是现场的 ):

 sizeof( char[func()] ) ; 

因为它们都是可变长度数组。 虽然,我认为其中任何一个都没有太多实际用途。

注意,可变长度数组包含在草案C99标准部分6.7.5.2 数组声明 6.7.5.2 第4段中

[…]如果size是一个整型常量表达式,并且元素类型具有已知的常量大小,则数组类型不是可变长度数组类型; 否则,数组类型是可变长度数组类型。

更新

在C11中,VLA案例的答案发生了变化,在某些情况下,未指定是否评估了大小表达式。 从6.7.6.2数组声明 6.7.6.2说:

[…]如果size表达式是sizeof运算符的操作数的一部分,并且更改size表达式的值不会影响运算符的结果,则无法指定是否计算size表达式。

例如,在这样的情况下( 见它直播 ):

 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运算符不对进行操作,而是对表达式的类型进行操作。 因此,当你编写sizeof(f()) ,它会对表达式f()类型进行操作,而这只是函数f的返回类型。 返回类型总是相同的,无论函数在实际执行时返回什么值。

在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 ,我首先创建一个A的实例,通过编写A() ,然后通过编写A().f()调用实例上的函数f ,但是没有这样的事情发生。

演示: http : //ideone.com/egPMi

这是另一个解释sizeof其他有趣属性的主题:

  • sizeof有两个论点

编译期间不能执行。 所以++i / i++不会发生。 sizeof(foo())也不会执行该函数但返回正确的类型。

sizeof()运算符仅给出数据类型的大小,它不计算内部元素。