代码之家  ›  专栏  ›  技术社区  ›  Anemoia

C,奇怪的优化

  •  12
  • Anemoia  · 技术社区  · 15 年前

    我在读我编译的C代码。

    这是我的代码:

    using(OleDbCommand insertCommand = new OleDbCommand("...", connection))
    {
       // do super stuff
    }
    

    但是!

    我们都知道一个用法被翻译成:

    {
        OleDbCommand insertCommand = new OleDbCommand("...", connection)
        try
        {
            //do super stuff
        }
        finally
        {
            if(insertCommand != null)
                ((IDisposable)insertCommand).Dispose();
        }
    }
    

    (因为oledbcommand是引用类型)。

    但是当我反编译我的程序集(用.NET 2.0编译)时,我在Resharper中得到了:

    try
    {
        insertCommand = new OleDbCommand("", connection);
    Label_0017:
        try
        {
           //do super stuff
        }
        finally
        {
        Label_0111:
            if ((insertCommand == null) != null)
            {
                goto Label_0122;
            }
            insertCommand.Dispose();
        Label_0122:;
        }
    

    我说的是这条线: if ((insertCommand == null) != null) .

    假设insertcommand为空。然后第一部分返回true。 (true != null) 退货 true . 那么,还是跳过处理?奇怪,非常奇怪。

    如果我在Visual Studio中粘贴此内容,Resharper已经警告我:表达式始终为真…

    谢谢!

    -克里斯托夫

    2 回复  |  直到 15 年前
        1
  •  12
  •   Eric Lippert    15 年前

    反编译程序有一个错误。这条线

    if ((insertCommand == null) != null) 
    

    应该被分解到

    if ((insertCommand == null) != false)
    

    它虽然冗长得不必要,但至少是正确的代码。

    反编译程序可能会执行不必要的冗长版本,因为C编译器经常选择发出

    if (x)
       Y();
    Z();
    

    就像你写的

    if (!x)
        goto L;
    Y();
    L: Z();
    

    由于为两个程序生成的代码是相同的,因此反编译器并不总是知道要显示哪个代码更为合理。

    意外的原因“!=false“是因为当我们生成IL来测试某个东西是否是真的时,我们能生成的最快、最紧凑的代码就是测试它是否是假的。在IL中,false被表示为零,并且有一个廉价的指令“这是零吗?”

        2
  •  0
  •   Tony    15 年前

    当您对代码进行反编译时,您不保证能返回原始代码。当.NET代码编译到IL时,它会被优化。有时,当应用程序将IL转换回C_时,您会看到一些疯狂。这并不意味着代码不起作用,而是应用程序(在本例中是Resharper)如何翻译IL。

    如果您担心它,我会直接查看IL,看看它是编译成什么的。

    附带说明:不保证将IL反编译为C或vb.net。:)

    另一个要尝试的产品是 Reflector

    推荐文章