提问人:Run 提问时间:8/4/2023 最后编辑:Guru StronRun 更新时间:8/5/2023 访问量:42
在编译时计算
evaluated at compile time
问:
两个例子有什么区别?
示例 1:int x = int.MaxValue + 1; // Compile-time error
例 2;int x = int.MaxValue; x = x + 1; // no Compile-time error
《A Nutshell》一书的作者在谈到第一个例子时说,在编译时计算的表达式总是经过溢出检查的。
我不明白第一个和第二个例子之间的区别。两者不是在编译时评估的,那么两者都应该产生相同的错误吗?
答:
两者不是在编译时评估的,那么两者都应该产生相同的错误吗?
不,编译器(据我所知)只计算常量表达式,第二个表达式不是一个。
所以在下文中:x + 1
int x = int.MaxValue;
x = x + 1; // no Compile-time error
不是常量表达式。即,如果您将其更改为:
const int x = int.MaxValue;
int x1 = x + 1;
它将产生编译时错误。
一些规范深入探讨:
当上述操作之一产生的结果太大而无法在目标类型中表示时,执行该操作的上下文将控制结果行为:
- 在已检查的上下文中,如果操作是常量表达式 (§12.23),则会发生编译时错误。否则,在运行时执行操作时,将引发 a。
System.OverflowException
在规范的 12.23 常量表达式部分:
常量表达式中只允许使用以下构造:
- 文本(包括文本)。
null
- 对类和结构类型成员的引用。
const
- 对枚举类型成员的引用。
- 对本地常量的引用。
- 带括号的子表达式,这些子表达式本身是常量表达式。
- 强制转换表达式。
checked
和表达式。unchecked
nameof
表达 式。- 预定义的 、 、 和 一元运算符。
+
–
!
~
- 预定义的 、 、 、 、 和 二元运算符。
+
–
*
/
%
<<
>>
&
|
^
&&
||
==
!=
<
>
<=
>=
- 条件运算符。
?:
sizeof
表达式,前提是 unmanaged-type 是 §23.6.9 中指定的类型之一,其返回常量值。sizeof
- 默认值表达式,前提是类型是上面列出的类型之一。
主要区别在于示例 2 是两个表达式。第一个赋值 int x,第二个赋值它。示例 2 可以改写为:
int x = int.MaxValue;
x = x + 1;
作者的观点是,编译器不会检查第二个表达式是否存在整数溢出。
评论
int.MaxValue
是一个常量值,因此编译器可以计算并确定它是否超出了 的范围。int.MaxValue + 1
int
编译器不够复杂,无法知道 是 ,计算并确定它是否溢出。x
int.MaxValue
x + 1
编译器不会“计算”第二个 - 它只是将表达式转换为在程序运行时计算的等效 IL 代码(这显然会在运行时溢出)。
如果第一个示例使用了未溢出的常量表达式(例如),编译器可以用 IL 中常量表达式的结果替换该表达式。int.MaxValue - 1
这就是“在编译时评估”的全部含义
评论