1

假设默认算术溢出(不)检查,以下代码

Action<Int32[]> action;

checked
{
    action = array =>
        Console.WriteLine(array[0] + array[1]);
}

var items = new[]
{
    Int32.MaxValue,
    Int32.MaxValue
};
action(items);

将导致

System.OverflowException:算术运算导致溢出..

如果我们将项目设置设置为/checked,并替换checked {unchecked {,则不会抛出异常。

那么,我们可以依靠这种行为,还是更安全array => unchecked (array[0] + array[1])

4

3 回答 3

1

在上一次正式发布的 C# 规范中,它说:

8.11 (...) 被检查的语句使块中的所有表达式在被检查的上下文中被计算,并且未被检查的语句导致块中的所有表达式被在未被检查的上下文中被计算。(...)

我会非常自信地说,这action将始终在检查/未检查的上下文中进行评估,这是您所看到的当前行为,我不希望这种情况在未来发生变化。

为了进一步扩展我的答案,如果您检查编译后的代码,您会发现语句Console.WriteLine(array[0] + array[1])内部checked实际上是编译为等效的,Console.WriteLine(checked (array[0] + array[1]))因此实际上不需要自己做,编译器无论如何都会做。

于 2017-04-05T08:11:19.210 回答
0

请记住这一点checkedunchecked更改编译器发出的指令。例如,在 IL 中有两个(实际上更多)add指令变体,其中一个变体忽略溢出,而另一个变体检查溢出。

由于它改变了发出的 IL,它必须应用。


例如这段代码:

    static void Main(string[] args)
    {
        int i = 0;
        int j = 1;
        int k;
        checked
        {
            k = i + j;
        }
        unchecked
        {
            k = i + j;
        }
        Console.ReadLine();
    }

发出这个 IL:

.method private hidebysig static void Main(string[] args) cil managed
{
    .entrypoint
    .maxstack 2
    .locals init (
        [0] int32 num,
        [1] int32 num2,
        [2] int32 num3)
    L_0000: nop 
    L_0001: ldc.i4.0 
    L_0002: stloc.0 
    L_0003: ldc.i4.1 
    L_0004: stloc.1 
    L_0005: nop 
    L_0006: ldloc.0 
    L_0007: ldloc.1 

    L_0008: add.ovf 

    L_0009: stloc.2 
    L_000a: nop 
    L_000b: nop 
    L_000c: ldloc.0 
    L_000d: ldloc.1 

    L_000e: add 

    L_000f: stloc.2 
    L_0010: nop 
    L_0011: call string [mscorlib]System.Console::ReadLine()
    L_0016: pop 
    L_0017: ret 
}

您可以在哪里看到发出的两条不同的指令。

于 2017-04-05T08:20:39.193 回答
0

最好将 C# 视为具有两组整数运算符,其中一组执行溢出检查,另一组不执行;“+”运算符是否绑定到“溢出检查加法”运算符或“包装加法”加法运算符由它是否出现在已检查或未检查的上下文中进行控制。运算符影响程序执行的唯一方法是选择哪些运算符绑定到像“+”这样的标记;这种绑定发生在编译器检查代码时,而不是在运行时。

于 2017-04-10T23:35:20.937 回答