Mik*_*her 21 c# optimization roslyn visual-studio-2015
昨天我在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()));
Run Code Online (Sandbox Code Playgroud)
我假设程序会打印,1|2|0但实际上是打印的1|2|3|0.
查看生成的IL代码(通过ILSpy),您可以看到它s.Pop() * 0被优化为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)
// ...
Run Code Online (Sandbox Code Playgroud)
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>()));
Run Code Online (Sandbox Code Playgroud)
首先,我在Windows 7下使用Visual Studio 2015 Update 3进行了测试,包括Release模式(/optimize)和调试模式以及各种目标框架(4.0,4.5,4.6和4.6.1).在所有8个案例中,结果是相同的(1|2|3|0).
然后我在Windows 7下使用Visual Studio 2013 Update 5进行了测试(再次使用发布/调试模式和目标框架的所有组合).令我惊讶的是,这里的声明没有被优化掉,产生了预期的结果1|2|0.
所以我可以得出结论,这种行为既不依赖于/optimize目标框架标志,也不依赖于使用的编译器版本.
出于兴趣,我在C++中编写了类似的代码,并使用当前的gcc版本进行编译.这里函数调用乘以零没有被优化掉并且函数被正确执行.
我认为这样的优化只有在stack.Pop()纯函数(它肯定不是)时才有效.但是我把这个错误称为错误,我认为这只是一个我不知道的功能?
这个"功能"是否记录在案,是否有(简单)方法来禁用此优化?
VSa*_*dov 12
是的,这肯定是一个错误.<expr>*0,如果<expr>有副作用,则不应优化为0.
谢谢你报告这个问题!!
您可以在https://github.com/dotnet/roslyn/issues/13486上跟踪错误/修复的进度.
| 归档时间: |
|
| 查看次数: |
590 次 |
| 最近记录: |