visual - tabla de multiplicar en c# windows form
El compilador de Roslyn optimiza la multiplicaciĆ³n de llamadas de funciĆ³n ausente con cero (1)
Sí, definitivamente es un error. <expr> * 0, no debe optimizarse en 0 si <expr> tiene efectos colaterales.
¡Gracias por informar el problema!
Puede seguir el progreso del error / solución en https://github.com/dotnet/roslyn/issues/13486
Ayer encontré este extraño comportamiento en mi código C #:
Stack<long> s = new Stack<long>();
s.Push(1); // stack contains [1]
s.Push(2); // stack contains [1|2]
s.Push(3); // stack contains [1|2|3]
s.Push(s.Pop() * 0); // stack should contain [1|2|0]
Console.WriteLine(string.Join("|", s.Reverse()));
Supuse que el programa imprimiría 1|2|0
pero de hecho imprimió 1|2|3|0
.
Al observar el código IL generado (a través de ILSpy), se puede ver que s.Pop() * 0
está optimizado para simplemente 0
:
// ...
IL_0022: ldloc.0
IL_0023: ldc.i4.0
IL_0024: conv.i8
IL_0025: callvirt instance void class [System]System.Collections.Generic.Stack`1<int64>::Push(!0)
// ...
Descompilación ILSpy :
Stack<long> s = new Stack<long>();
s.Push(1L);
s.Push(2L);
s.Push(3L);
s.Push(0L); // <- the offending line
Console.WriteLine(string.Join<long>("|", s.Reverse<long>()));
Primero probé esto inicialmente en Windows 7 con Visual Studio 2015 Update 3 con el modo Release ( /optimize
) y el modo Debug y con varios frameworks de destino (4.0, 4.5, 4.6 y 4.6.1). En los 8 casos, el resultado fue el mismo ( 1|2|3|0
).
Luego lo probé en Windows 7 con Visual Studio 2013 Update 5 (de nuevo con todas las combinaciones de modo Release / Debug y framework objetivo). Para mi sorpresa, la declaración aquí no está optimizada y arroja el resultado esperado 1|2|0
.
Entonces, puedo concluir que este comportamiento no depende de /optimize
ni del indicador de marco objetivo, sino más bien de la versión del compilador utilizada.
Fuera de interés, escribí un código similar en C ++ y lo compilé con la versión actual de gcc. Aquí una llamada de función multiplicada por cero no se optimiza y la función se ejecuta correctamente.
Creo que tal optimización solo sería válida si stack.Pop()
fuera una función pura (que definitivamente no lo es). Pero dudo de llamar a esto un error, ¿supongo que es solo una característica desconocida para mí?
¿Está documentada esta "característica" en algún lugar y existe una forma (fácil) de desactivar esta optimización?