在编译时评估

huangapple go评论71阅读模式
英文:

evaluated at compile time

问题

两个示例之间有什么区别?

示例1:
int x = int.MaxValue + 1; // 编译时错误

示例2:
int x = int.MaxValue; x = x + 1; // 没有编译时错误

《A Nutshell》书的作者关于第一个示例说道在编译时评估的表达式总是会进行溢出检查。

我不明白第一个示例和第二个示例之间的区别。两者都是在编译时评估的,所以应该都会产生相同的错误,对吗?

英文:

What the difference between two examples?

example 1:
int x = int.MaxValue + 1; // Compile-time error

example 2;
int x = int.MaxValue;
x = x + 1; // no Compile-time error

The Author of A Nutshell book said about the first example that expressions evaluated at compile time are always overflow-checked.

I didn't understand the difference between the first and second examples. Isn't both evaluated at compile time, so should both produce the same error?

答案1

得分: 5

int.MaxValue是一个常量值,因此编译器可以计算int.MaxValue + 1并确定它超出了int的范围。

编译器并不足够智能,无法知道xint.MaxValue,计算x + 1并确定它溢出。

编译器不会“评估”第二个表达式 - 它只是将表达式转换为在程序运行时评估的等效IL代码(显然会在运行时溢出)。

如果第一个示例使用不会溢出的常量表达式(例如int.MaxValue - 1),编译器可以将表达式替换为IL中常量表达式的结果。

这就是所谓的“在编译时评估”的含义。

英文:

int.MaxValue is a constant value, so the compiler can calculate int.MaxValue + 1 and determine that it overflows the range of int.

The compiler is not sophisticated enough to know that x is int.MaxValue, calculate x + 1 and determine that it overflows.

The compiler does not "evaluate" the second - it just turns the expressions into the equivalent IL code that is evaluated when the program runs (which would obviously overflow at runtime).

If the first example used a constant expression that did not overflow (e.g. int.MaxValue - 1), the compiler could replace the expression with the result of the constant expression in the IL.

That's all that's meant by "evaluated at compile-time"

答案2

得分: 1

> Isn't both evaluated at compile time, so should both produce the same error?

不是,编译器(据我所知)只评估常量表达式,而第二个不是常量表达式。

所以在以下代码中的 x + 1

int x = int.MaxValue; 
x = x + 1; // 没有编译时错误

不是一个常量表达式。换句话说,如果你将它改为:

const int x = int.MaxValue; 
int x1 = x + 1; 

它会产生编译时错误。

稍微深入规范的部分:

来自规范:12.8.19 checked 和 unchecked 操作符

> 当上述操作之一产生无法在目标类型中表示的结果时,操作执行的上下文控制了结果的行为:

> - 在 checked 上下文中,如果操作是常量表达式(§12.23),则会产生编译时错误。否则,当在运行时执行操作时,会引发 System.OverflowException

而在规范的12.23 常量表达式部分:

> 只有以下结构在常量表达式中允许:
>
> - 字面量(包括 null 字面量)。
> - 对类和结构类型的 const 成员的引用。
> - 对枚举类型的成员的引用。
> - 对本地常量的引用。
> - 带括号的子表达式,它们本身是常量表达式。
> - 强制转换表达式。
> - checkedunchecked 表达式。
> - nameof 表达式。
> - 预定义的一元运算符 +!~
> - 预定义的二元运算符 +*/%<<>>&|^&&||==!=<><=>=
> - ?: 条件运算符。
> - sizeof 表达式,前提是非托管类型是§23.6.9中指定的返回常量值的类型之一。
> - 默认值表达式,前提是类型是上面列出的类型之一。

英文:

> Isn't both evaluated at compile time, so should both produce the same error?

No, compiler (as far as I know) evaluates only the constant expressions and the second isn't one.

So x + 1 in the following:

int x = int.MaxValue; 
x = x + 1; // no Compile-time error

Is not a constant expression. I.e. if you will change it to:

const int x = int.MaxValue; 
int x1 = x + 1; 

it will produce the compile-time error.

A bit of specification deep dive:

From specification: 12.8.19 The checked and unchecked operators:

> When one of the above operations produces a result that is too large to represent in the destination type, the context in which the operation is performed controls the resulting behavior:

> - In a checked context, if the operation is a constant expression (§12.23), a compile-time error occurs. Otherwise, when the operation is performed at run-time, a System.OverflowException is thrown.

And in the 12.23 Constant expressions part of spec:

> Only the following constructs are permitted in constant expressions:
>
> - Literals (including the null literal).
> - References to const members of class and struct types.
> - References to members of enumeration types.
> - References to local constants.
> - Parenthesized subexpressions, which are themselves constant expressions.
> - Cast expressions.
> - checked and unchecked expressions.
> - nameof expressions.
> - The predefined +, , !, and ~ unary operators.
> - The predefined +, , *, /, %, <<, >>, &, |, ^, &&, ||, ==, !=, <, >, <=, and >= binary operators.
> - The ?: conditional operator.
> - sizeof expressions, provided the unmanaged-type is one of the types specified in §23.6.9 for which sizeof returns a constant value.
> - Default value expressions, provided the type is one of the types listed above.

答案3

得分: -3

关键区别在于示例2有两个表达式。第一个将int x赋值,第二个将其递增。示例2可以重写为:

int x = int.MaxValue;
x = x + 1;

作者要表达的观点是编译器不会检查第二个表达式是否发生整数溢出。

英文:

The key difference is that example 2 is two expressions. The first assigns the int x, the second increments it. Example 2 can be re-written as:

int x = int.MaxValue;
x = x + 1;

The point that the author is making is that the compiler doesn't check the second expression for integer overflow.

huangapple
  • 本文由 发表于 2023年8月4日 23:54:02
  • 转载请务必保留本文链接:https://go.coder-hub.com/76837487.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定