为什么编译器会评估与运行时不同的余数MinValue%-1?

Jep*_*sen 22 c# operators overflowexception compiler-bug modulus

我认为这看起来像C#编译器中的一个错误.

考虑这段代码(在方法内):

const long dividend = long.MinValue;
const long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)

它编译时没有错误(或警告).好像是一个bug.运行时,0在控制台上打印.

然后没有const,代码:

long dividend = long.MinValue;
long divisor = -1L;
Console.WriteLine(dividend % divisor);
Run Code Online (Sandbox Code Playgroud)

当它运行时,它正确地导致OverflowException被抛出.

C#语言规范专门提到了这个案例,并说System.OverflowException将抛出一个.它不依赖于上下文checkedunchecked似乎(也是与余数运算符的编译时常量操作数的错误与checked和相同unchecked).

int(System.Int32),而不仅仅是long(System.Int64)发生同样的错误.

相比之下,编译器处理dividend / divisorconst操作数比要好得多dividend % divisor.

我的问题:

我是对的,这是一个错误吗?如果是,它是一个众所周知的错误,他们不希望修复(因为向后兼容性,即使使用% -1编译时常量相当愚蠢-1)?或者我们应该报告它,以便他们可以在即将推出的C#编译器版本中修复它?

Han*_*ant 19

这个角落案例在编译器中得到了非常具体的解决.Roslyn源中最相关的注释和代码:

// Although remainder and division always overflow at runtime with arguments int.MinValue/long.MinValue and -1     
// (regardless of checked context) the constant folding behavior is different.     
// Remainder never overflows at compile time while division does.    
newValue = FoldNeverOverflowBinaryOperators(kind, valueLeft, valueRight);
Run Code Online (Sandbox Code Playgroud)

和:

// MinValue % -1 always overflows at runtime but never at compile time    
case BinaryOperatorKind.IntRemainder:
    return (valueRight.Int32Value != -1) ? valueLeft.Int32Value % valueRight.Int32Value : 0;
case BinaryOperatorKind.LongRemainder:
    return (valueRight.Int64Value != -1) ? valueLeft.Int64Value % valueRight.Int64Value : 0;
Run Code Online (Sandbox Code Playgroud)

还有遗留C++版本编译器的行为,一直回到版本1.从SSCLI v1.0发行版,clr/src/csharp/sccomp/fncbind.cpp源文件:

case EK_MOD:
    // if we don't check this, then 0x80000000 % -1 will cause an exception...
    if (d2 == -1) {
        result = 0;
    } else {
        result = d1 % d2;
    }
    break;
Run Code Online (Sandbox Code Playgroud)

因此得出的结论是,这一点并没有被忽视或遗忘,至少对于编译器工作的程序员而言,它可能被认为是C#语言规范中不够精确的语言.更多关于这篇帖子中这个杀手捅引起的运行时问题.