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

时间:2011-11-22 11:07:17

标签: c sizeof

以下是在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

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

10 个答案:

答案 0 :(得分:515)

来自C99 Standard(强调是我的)

  

6.5.3.4/2

     

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

答案 1 :(得分:181)

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 :(得分:47)

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

6.5.3.4:

  

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

简而言之:可变长度数组,在运行时运行。 (注意:Variable Length Arrays是一个特定功能 - 不是使用malloc(3)分配的数组。)否则,只计算表达式的类型,并在编译时计算。< / p>

答案 3 :(得分:33)

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

(sizeof x)  //this also works

答案 4 :(得分:19)

注意

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

原始

除了variable length arrays sizeof 之外,它不会评估其参数。我们可以从草案C99标准部分6.5.3.4 sizeof运算符 2 中看到:

  

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

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

sizeof( char[x++]  ) ;

而且确实如此,这样的事情也可行( See them both live ):

sizeof( char[func()]  ) ;

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

请注意,draft C99 standard部分6.7.5.2 数组声明符第4段中涵盖了可变长度数组:

  

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

更新

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

  

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

例如在这种情况下( see it live ):

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

答案 5 :(得分:10)

编译期间不能执行。因此++i / i++不会发生。同样sizeof(foo())将不执行该函数,但返回正确的类型。

答案 6 :(得分:10)

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

也就是说,如果仅在f中使用它,则不需要定义函数sizeof。这种技术主要用于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

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

sizeof在编译时运行,但是x++仅在运行时可以求值。为了解决这个问题,C ++标准规定sizeof的操作数不进行评估(VLA除外)。 C标准说:

  

如果[sizeof的操作数的类型是可变长度数组类型,则对操作数求值;否则,不对操作数求值,结果为整数常量。

答案 9 :(得分:0)

这里的这一行:

Oracle (any version)    org.hibernate.dialect.OracleDialect
Oracle9i                org.hibernate.dialect.Oracle9iDialect
Oracle10g               org.hibernate.dialect.Oracle10gDialect

导致UB。 printf("%d and ", sizeof(x++)); // note 1 需要类型 %d 而不是 int。获得 UB 后,行为未定义,包括写入标准输出的字节。

如果您将 size_t 替换为 %d 或将值强制转换为 %zu 来解决该问题,但不能同时使用这两种方法,您仍然不会增加 int,但这是一个不同的问题,应该在不同的问题中提出。