一元:为什么一元在 c# 中的行为因 c/c++ 而异

Unary: Why unary's behavior in c# varies with c/c++

本文关键字:一元 而异 c++ 为什么      更新时间:2023-10-16

可能重复:
未定义、未指定和实现定义的行为
未定义的行为和序列点
Pre&C、C++、Java和&C#

我有这个代码片段:

int x = 2;
int y = x + 4 * ++x;
// what is y???

当我在c/c++中编译和测试它时,我会得到:

// C/C++
y is 15

但是通过c#我会得到

// C#
y is 14

为什么


IL的一部分是:

locals init ([0] int32 x,
[1] int32 y)
IL_0000: nop
IL_0001: ldc.i4.2
IL_0002: stloc.0
IL_0003: ldloc.0
IL_0004: ldc.i4.4
IL_0005: ldloc.0
IL_0006: ldc.i4.1
IL_0007: add
IL_0008: dup
IL_0009: stloc.0
IL_000a: mul
IL_000b: add
IL_000c: stloc.1
IL_000d: ldloca.s y
int y = x + 4 * ++x;

在C和C++中,每个操作数的求值顺序是未指定的,这意味着x4*++x可以在另一个之前求值。由于操作数的求值顺序未指定,因此整个表达式的结果也未指定。

如果在4*++x之前评估x,则y将计算为:

int y = x + 4 * ++x; //original
int y = 2 + 4 * ++x  //evaluate x first
      = 2 + (4 * 3)  //evaluate 4 *++x then
      = 14;

类似地,如果在x之前评估4*++x,则

int y = x + 4 * ++x; //original
int y = x + (4*3)  //evaluate 4 * ++x first
      = 3 + 12   //evaluate x then  (x is incremented)
      = 15;

在C#中,操作数需要从左到右求值,因此您总是得到第一个行为,结果为14。

实际上,在C++中,您只会得到未定义的行为,因为表达式的求值顺序并不总是指定的,所以不清楚第一次使用x读取的是旧值还是新值。两者都是可能的,事实上,任何事情都有可能,因为标准明确规定了发生的事情是不确定的。

C#作为一种安全的语言,不允许出现这种情况,因此更严格地定义了求值顺序。