c# - multidimensionales - ¿Por qué el valor de enumeración de una matriz multidimensional no es igual a sí mismo?
matriz de 3 dimensiones (2)
Considerar:
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
}
}
¿Cómo se puede explicar esto? Ocurre en compilaciones de depuración en Visual Studio 2015 cuando se ejecuta en el xIT JIT. Una compilación de lanzamiento o ejecución en el x64 JIT imprime True como se esperaba.
Para reproducir desde la línea de comando:
csc Test.cs /platform:x86 /debug
(
/debug:pdbonly
,
/debug:portable
y
/debug:full
también se reproducen).
Consideremos la declaración de OP:
enum State : sbyte { OK = 0, BUG = -1 }
Dado que el error solo ocurre cuando
BUG
es negativo (de -128 a -1) y State es una enumeración de
byte firmado
, comencé a suponer que había un problema de transmisión en alguna parte.
Si ejecuta esto:
Console.WriteLine((sbyte)s[0, 0]);
Console.WriteLine((sbyte)State.BUG);
Console.WriteLine(s[0, 0]);
unchecked
{
Console.WriteLine((byte) State.BUG);
}
saldrá:
255
-1
ERROR
255
Por una razón que ignoro
(a partir de ahora)
s[0, 0]
se convierte a un byte antes de la evaluación y es por eso que afirma que
a == s[0,0]
es falso.
Encontraste un error de generación de código en el jitter .NET 4 x86. Es muy inusual, solo falla cuando el código no está optimizado. El código de máquina se ve así:
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
Un asunto pesado con muchos temporales y duplicación de código, eso es normal para el código no optimizado. La instrucción en 013F04B8 es notable, ahí es donde ocurre la conversión necesaria de sbyte a un entero de 32 bits. La función auxiliar de obtención de matriz devolvió 0x0000000FF, igual a State.BUG, y eso debe convertirse a -1 (0xFFFFFFFF) antes de que se pueda comparar el valor. La instrucción MOVSX es una instrucción Sign eXtension.
Lo mismo sucede nuevamente en 013F04CC, pero esta vez no hay instrucciones MOVSX para hacer la misma conversión. Ahí es donde se caen los chips, la instrucción CMP compara 0xFFFFFFFF con 0x000000FF y eso es falso. Entonces, este es un error de omisión, el generador de código no pudo emitir MOVSX nuevamente para realizar la misma conversión de sbyte a int.
Lo que es particularmente inusual acerca de este error es que funciona correctamente cuando habilita el optimizador, ahora sabe usar MOVSX en ambos casos.
La razón probable de que este error no se haya detectado durante tanto tiempo es el uso de sbyte como el tipo base de la enumeración. Muy raro de hacer. El uso de una matriz multidimensional también es instrumental, la combinación es fatal.
De lo contrario, diría que es un error bastante crítico. Es difícil adivinar cuán extendido podría ser, solo tengo que probar la fluctuación de fase 4.6.1 x86. El x64 y el jitter 3.5 x86 generan un código muy diferente y evitan este error. La solución temporal para continuar es eliminar sbyte como el tipo base enum y dejar que sea el valor predeterminado, int , para que no sea necesaria una extensión de signo.
Puede presentar el error en connect.microsoft.com, el enlace a este Q + A debería ser suficiente para decirles todo lo que necesitan saber. Avísame si no quieres tomarte el tiempo y yo me encargaré.