为什么多维数组的枚举值不等于自身?

考虑:

using System;

public class Test
{
    enum State : sbyte { OK = 0, BUG = -1 }

    static void Main(string[] args)
    {
        var s = new State[1, 1];
        s[0, 0] = State.BUG;
        State a = s[0, 0];
        Console.WriteLine(a == s[0, 0]); // False
    }
}

这怎么解释? 它在运行在x86 JIT中的Visual Studio 2015中的调试版本中发生。 在x64 JIT中生成或运行的发行版按预期打印为True。

从命令行重现:

csc Test.cs /platform:x86 /debug

/debug:pdbonly/debug:portable/debug:full也可以重现。)


您在.NET 4 x86抖动中发现了代码生成错误。 这是非常不寻常的一种,只有在代码未被优化时才会失败。 机器代码如下所示:

        State a = s[0, 0];
013F04A9  push        0                            ; index 2 = 0
013F04AB  mov         ecx,dword ptr [ebp-40h]      ; s[] reference
013F04AE  xor         edx,edx                      ; index 1 = 0
013F04B0  call        013F0058                     ; eax = s[0, 0]
013F04B5  mov         dword ptr [ebp-4Ch],eax      ; $temp1 = eax 
013F04B8  movsx       eax,byte ptr [ebp-4Ch]       ; convert sbyte to int
013F04BC  mov         dword ptr [ebp-44h],eax      ; a = s[0, 0]
        Console.WriteLine(a == s[0, 0]); // False
013F04BF  mov         eax,dword ptr [ebp-44h]      ; a
013F04C2  mov         dword ptr [ebp-50h],eax      ; $temp2 = a
013F04C5  push        0                            ; index 2 = 0
013F04C7  mov         ecx,dword ptr [ebp-40h]      ; s[] reference 
013F04CA  xor         edx,edx                      ; index 1 = 0
013F04CC  call        013F0058                     ; eax = s[0, 0]
013F04D1  mov         dword ptr [ebp-54h],eax      ; $temp3 = eax 
                                               ; <=== Bug here!
013F04D4  mov         eax,dword ptr [ebp-50h]      ; a == s[0, 0] 
013F04D7  cmp         eax,dword ptr [ebp-54h]  
013F04DA  sete        cl  
013F04DD  movzx       ecx,cl  
013F04E0  call        731C28F4  

由于大量临时代码和代码重复而导致事务繁琐,这对未优化的代码来说是正常的。 013F04B8处的指令值得注意,即发生从sbyte到32位整数的必要转换。 数组getter辅助函数返回0x0000000FF,等于State.BUG,并且在可以比较值之前需要将其转换为-1(0xFFFFFFFF)。 MOVSX指令是Sign eXtension指令。

013F04CC再次发生同样的事情,但这次没有 MOVSX指令进行相同的转换。 这是芯片崩溃的地方,CMP指令将0xFFFFFFFF与0x000000FF进行比较,这是错误的。 所以这是一个遗漏的错误,代码生成器未能再次发出MOVSX来执行相同的sbyte到int转换。

这个bug特别不寻常的是,当你启用优化器时,它会正常工作,现在知道在这两种情况下都使用MOVSX。

这个bug未被检测到这么久的可能原因是使用了sbyte作为枚举的基类型。 相当罕见。 使用多维数组也是有用的,组合是致命的。

否则,我会说一个相当重要的错误。 很难猜到它的广泛程度,我只有4.6.1 x86抖动才能测试。 x64和3.5 x86抖动会生成非常不同的代码并避免此错误。 继续进行的临时解决方法是删除sbyte作为枚举基类型,并将其设置为默认值int,因此不需要任何符号扩展。

你可以在connect.microsoft.com上提交bug,链接到这个Q + A应该足以告诉他们他们需要知道的一切。 如果你不想花时间,我会照顾它,让我知道。


让我们考虑OP的声明:

enum State : sbyte { OK = 0, BUG = -1 }

由于错误只发生在BUG为负数时(从-128到-1),State是有符号字节的枚举,我开始假设某处存在投射问题。

如果你运行这个:

Console.WriteLine((sbyte)s[0, 0]);
Console.WriteLine((sbyte)State.BUG);
Console.WriteLine(s[0, 0]);
unchecked
{
    Console.WriteLine((byte) State.BUG);
}

它会输出:

255

-1

BUG

255

由于我忽略的原因(截至目前) s[0, 0]在评估之前被转换为字节,这就是为什么它声称a == s[0,0]为假。

链接地址: http://www.djcxy.com/p/66313.html

上一篇: Why is the enumeration value from a multi dimensional array not equal to itself?

下一篇: Different results for pow on x86 and x64