提问



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


#include 

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


谁能解释为什么x注1 之后没有增加?

最佳参考


从C99标准(重点是我的)[43]



??6.5.3.4/2

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


其它参考1


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


因为short在我的机器上占用2个字节。


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


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


8作为输出。

其它参考2


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


6.5.3.4:



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



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

其它参考3


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


(sizeof x)  //this also works

其它参考4


注意


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


原始


除了可变长度数组 sizeof 不评估其参数。我们可以从草案C99标准部分6.5.3.4 sizeof运算符段 2 中看到这一点,其中说:[45]



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




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


sizeof( char[x++]  ) ;


事实上,这样的事情也会起作用(看到他们都活着):[46]


sizeof( char[func()]  ) ;


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


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



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



更新


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



??[[...]] size表达式是sizeof的操作数的一部分
??运算符和更改大小表达式的值不会
??影响运算符的结果,是否未指定
??评估大小表达式。



例如,在这种情况下(看到它):[48]


sizeof( int (*)[x++] )

其它参考5


由于未评估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 [49]


也就是说,如果仅在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的实例,然后通过写入在实例上调用函数f A().f(),但没有这样的事情发生。


演示:http://ideone.com/egPMi [50]


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



  • sizeof采取两个论点


其它参考6


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

其它参考7


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