c# - 了解编译器优化

标签 c# .net compiler-construction compiler-optimization

我试图了解编译器对非常简单的代码段做了什么:

if (group.ImageHeight > 1 && group.ImageWidth > 1)
{ //No code exists between the braces
}

Debug 配置中编译后,然后反编译我看到了这个:

if (group.ImageHeight <= 1 || group.ImageWidth <= 1);

反编译 Release 配置结果

if (group.ImageHeight > 1)
{
  int imageWidth = group.ImageWidth;
}

更完整(原始)代码:

public class Group 
{
  public int ImageHeight { get; set; }
  public int ImageWidth { get; set; }
}

//The following belongs to a different project than `Group`
static void Main(string[] args)
{
  Group group = new Group();
  MyMethod(group);
}
static void MyMethod(Group group)
{
    if (group.ImageHeight > 1 && group.ImageWidth > 1)
    { 
    }
}

到目前为止,这是我的猜测和观察:

  • 当我第一次开始这个时,我希望编译器完全放弃整个语句。我认为这不是因为对属性的评估可能会产生副作用。
  • 我认为 group 类型属于我的解决方案中的另一个项目很重要。我这样说是因为编译器可能无法“知道”将来评估属性的副作用是什么。例如,我可以在编译后替换包含 group 定义的 DLL。
  • Release 配置中,可能的副作用似乎与我的代码相同:评估 ImageHeight 并且如果满足 > 1条件将评估 ImageWidth(尽管通过赋值而不是比较)

现在,对于我的具体问题:

  • 为什么 Release 配置使用赋值 (int imageWidth = group.ImageWidth) 而不是我原来的比较?运行作业是否更快?
  • 为什么Debug配置完全改变了副作用的可能性?在此配置中,将始终评估 ImageHeightImageWidth

最佳答案

对于第一个具体问题。当你在 sharplab.io 上查看 IL 时 简单的赋值是 1 条比较指令。谁的“then”和“else”将指向相同的指令(在本例中为 IL_0012),因此比较不需要调用函数,两次弹出就足够了。奇怪的是只加载将被立即丢弃的 Int32 常量 1。

如果 (group.ImageHeight > 1)

IL_0000: ldarg.0
IL_0001: callvirt instance int32 Group::get_ImageHeight()
IL_0006: ldc.i4.1
IL_0007: ble.s IL_0012

int imageWidth = group.ImageWidth;

IL_0009: ldarg.0
IL_000a: callvirt instance int32 Group::get_ImageWidth()
IL_000f: ldc.i4.1
IL_0010: pop
IL_0011: pop

IL_0012: ret

第二个具体问题。如果您在具有 Debug模式的同一页面上查看 IL,您会发现,代码是相同的,只有一些额外的调试指令和比较本身,因此您可以在调试器中查看它的结果。

IL_0000: nop
IL_0001: ldarg.0
IL_0002: callvirt instance int32 Group::get_ImageHeight()
IL_0007: ldc.i4.1
IL_0008: ble.s IL_0015

IL_000a: ldarg.0
IL_000b: callvirt instance int32 Group::get_ImageWidth()
IL_0010: ldc.i4.1
IL_0011: cgt
IL_0013: br.s IL_0016

IL_0015: ldc.i4.0

IL_0016: stloc.0
        // sequence point: hidden
IL_0017: ldloc.0
IL_0018: brfalse.s IL_001c

IL_001a: nop
IL_001b: nop

IL_001c: ret

关于c# - 了解编译器优化,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54258811/

相关文章:

.net - 什么时候应该选择IsolatedStorage和AppData文件存储?

c - Sys V ABI 规范(i386 和 AMD64)中描述的标准 "Function Calling Sequence"是否适用于静态 C 函数?

c# - Unity3D最好的脚本语言是什么

c# - Razor 智能感知在 vs2013 中不起作用

c# - EntityFramework 级联更新

c# - 在文本框失败时以红色突出显示的位置实现验证

c++ - 如何修复 Turbo C++ 错误 "Cannot open include file: graphics.h: no such files or director"

c# - C#中事件的内部设计

c# - 使用 linq 获取属性

c# - 将 Picturebox 图像发送到您的默认电子邮件