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

Nei*_*val 494 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;
}
Run Code Online (Sandbox Code Playgroud)

x执行注释1后,我希望是6 .但是,输出是:

4 and 5
Run Code Online (Sandbox Code Playgroud)

有人可以解释为什么x注1后没有增加?

pmg*_*pmg 520

C99标准(重点是我的)

6.5.3.4/2

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

  • "如果操作数的类型是可变长度数组类型,则操作数被评估"哇!我从未意识到这一点 (51认同)
  • 变长数组是一个声明的数组,其大小是编译期间未知的值,例如,如果从stdin读取`N`并使`int array [N]`.这是C99功能之一,在C++中不可用. (37认同)
  • @LegendofCage,特别是这意味着在诸如`sizeof(int [++ x])之类的东西(真的,真的是一个坏主意,无论如何),可以评估`++`. (21认同)
  • 变长数组类型是什么意思?那确实意味着操作数是一个数组?这种情况下的代码不是数组.你能为我清理一下吗? (5认同)
  • 请参阅[http://ideone.com/Q89QP](http://ideone.com/Q89QP)中使用的VLA示例. (3认同)
  • @Joe Wreschnig:它由`gcc`,`clang`和https://ideone.com/Pf7iF评估 (3认同)
  • @JensGustedt:`ints [++ x]`会有类型(例如)`int`,而不是VLA类型,因此不会被评估.你必须做一些像`sizeof(x ++?ints1:ints2)这样的东西,两者都是VLA,以便用满足该规则的副作用进行评估. (2认同)

cod*_*ict 186

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;
}
Run Code Online (Sandbox Code Playgroud)

输出:

2
Run Code Online (Sandbox Code Playgroud)

作为short占据我的机器上2个字节.

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

double func(short x) {
// rest all same
Run Code Online (Sandbox Code Playgroud)

8作为输出.

  • 只是有时 - 如果可能的话,它是编译时间. (12认同)
  • -1,因为这与被接受的(和正确的)答案相矛盾,并没有引用标准. (10认同)

sar*_*old 47

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

6.5.3.4:

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

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


hug*_*omg 33

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

(sizeof x)  //this also works
Run Code Online (Sandbox Code Playgroud)

  • @phresnel:这只是为了说明sizeof是"怪异的"并且不受正常函数规则的约束.无论如何,我编辑了帖子,以消除与正常的运行时运算符(如+(+)和( - ))可能的混淆 (5认同)
  • @Gaotter:是的,额外的括号被忽略:http://codepad.org/fhdjYhzV (4认同)

Sha*_*our 21

注意

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

原版的

除了可变长度数组, sizeof不会评估其参数.我们可以从C99标准部分草案中看到这一点:6.5.3.4 运营商2尺寸说:

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

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

sizeof( char[x++]  ) ;
Run Code Online (Sandbox Code Playgroud)

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

sizeof( char[func()]  ) ;
Run Code Online (Sandbox Code Playgroud)

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

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

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

更新

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

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

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

sizeof( int (*)[x++] )
Run Code Online (Sandbox Code Playgroud)


Naw*_*waz 11

由于sizeof未评估运算符的操作数,您可以执行以下操作:

int f(); //no definition, which means we cannot call it

int main(void) {
        printf("%d", sizeof(f()) );  //no linker error
        return 0;
}
Run Code Online (Sandbox Code Playgroud)

在线演示: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;
}
Run Code Online (Sandbox Code Playgroud)

然而,看起来sizeof,我首先A通过编写创建一个实例,A()然后通过写入调用f实例上的函数A().f(),但是没有这样的事情发生.

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

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


rak*_*esh 10

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

  • "_在编译过程中不能执行._"你的意思是什么? (2认同)