关于C#:为什么sizeof(x ++)不能增加x?

Why does sizeof(x++) not increment x?

下面是DEV C++窗口中编译的代码:

1
2
3
4
5
6
7
8
9
#include <stdio.h>

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

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

1
4 and 5

有人能解释为什么在注1之后x不递增吗?


根据C99标准(重点是我的)

6.5.3.4/2

The sizeof operator yields the size (in bytes) of its operand, which may be an expression or the parenthesized name of a type. The size is determined from the type of the operand. The result is an integer. If the type of the operand is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.


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

1
2
3
4
5
6
7
8
9
10
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;
}

输出:

1
2

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

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

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

将给予8作为输出。


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

5.5.3.4:

The sizeof operator yields the size (in bytes) of its operand, which may be an
expression or the parenthesized name of a type. The size is determined from the type of
the operand. The result is an integer. If the type of the operand is a variable length array
type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an
integer constant.

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


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

1
(sizeof x)  //this also works


注释

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

原件

除了可变长度数组之外,sizeof不计算其参数。我们可以从草案C99标准部分6.5.3.4中看到这一点。操作员第2段的尺寸表示:

The sizeof operator yields the size (in bytes) of its operand, which may be an
expression or the parenthesized name of a type. The size is determined from the type of
the operand. The result is an integer. If the type of the operand is a variable length array
type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an
integer constant.

一条评论(现在已删除)询问这样的东西是否会在运行时进行评估:

1
sizeof( char[x++]  ) ;

事实上,这样的事情也会奏效(看到他们都活下来):

1
sizeof( char[func()]  ) ;

因为它们都是可变长度的数组。不过,我认为这两种方法都没有多大的实际用途。

注:可变长度阵列包含在草案C99标准节6.7.5.2阵列声明器第4段中:

[...] If the size is an integer constant expression and the element type has a known constant size, the array type is not a variable length array type; otherwise, the array type is a variable length array type.

更新

在C11中,VLA情况的答案会更改,在某些情况下,不确定是否计算大小表达式。从6.7.6.2节数组声明器中,该声明器表示:

[...]Where a size expression is part of the operand of a sizeof
operator and changing the value of the size expression would not
affect the result of the operator, it is unspecified whether or not
the size expression is evaluated.

例如,在这样的情况下(现场查看):

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


由于不计算sizeof运算符的操作数,可以这样做:

1
2
3
4
5
6
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++中,EDOCX1×0的操作数也没有被评估。

为什么会这样?它的工作是因为sizeof运算符不对值进行操作,而是对表达式的类型进行操作。因此,当您编写sizeof(f())时,它在表达式f()的类型上运行,它只是函数f的返回类型。返回类型总是相同的,无论函数实际执行时返回的值是什么。

在C++中,你甚至可以这样做:

1
2
3
4
5
6
7
8
9
10
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


编译期间无法执行。所以不会发生++ii++的情况。另外,sizeof(foo())不会执行函数,而是返回正确的类型。


sizeof在编译时运行,但x++只能在运行时进行评估。为了解决这个问题,C++标准规定EDCOX1〔0〕的操作数不被评估(除了VLAs)。C标准规定:

If the type of the operand [of sizeof] is a variable length array type, the operand is evaluated; otherwise, the operand is not evaluated and the result is an integer constant.


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