首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >以"1“结尾的变量在ILSpy中删除"1”。为什么?

以"1“结尾的变量在ILSpy中删除"1”。为什么?
EN

Stack Overflow用户
提问于 2014-09-05 18:27:56
回答 2查看 568关注 0票数 14

为了探索C#编译器如何优化代码,我创建了一个简单的测试应用程序。通过每次测试更改,我已经编译了应用程序,然后在ILSpy中打开了二进制文件。

我只是注意到,对我来说,这很奇怪。显然,这是有意的,但是,我想不出编译器为什么要这么做的好理由。

考虑以下代码:

代码语言:javascript
复制
static void Main(string[] args)
{
    int test_1 = 1;
    int test_2 = 0;
    int test_3 = 0;

    if (test_1 == 1) Console.Write(1);
    else if (test_2 == 1) Console.Write(1);
    else if (test_3 == 1) Console.Write(2);
    else Console.Write("x");
}

没有意义的代码,但是我编写这个代码是为了了解ILSpy将如何解释if语句。

然而,当我编译/解压缩这段代码时,我确实注意到了一些让我抓狂的东西。我的第一个变量test_1被优化为test_!为什么C#编译器会这么做?

为了进行全面检查,这是我在ILSpy中看到的ILSpy的输出。

代码语言:javascript
复制
private static void Main(string[] args)
{
    int test_ = 1; //Where did the "1" go at the end of the variable name???
    int test_2 = 0;
    int test_3 = 0;
    if (test_ == 1)
    {
        Console.Write(1);
    }
    else
    {
        if (test_2 == 1)
        {
            Console.Write(1);
        }
        else
        {
            if (test_3 == 1)
            {
                Console.Write(2);
            }
            else
            {
                Console.Write("x");
            }
        }
    }
}

更新

显然,在检查IL之后,这是ILSpy的问题,而不是C#编译器的问题。尤金·波茨卡尔( Eugene Podskal )对我最初的评论和观察给出了一个很好的答案。但是,我想知道这是否是ILSpy中的一个bug,或者这是否是有意的功能。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2014-09-06 15:11:45

嗯,这是个虫子。这并不是什么错误,也不太可能有人为此提交了错误报告。请注意,尤金的回答非常误导人。ildasm.exe非常聪明,能够知道如何定位程序集的PDB文件并检索程序集的调试信息。它包括局部变量的名称。

对于反汇编程序来说,这通常不是一种奢侈。这些名称实际上并不存在于程序集本身中,它们总是在没有PDB的情况下完成任务。您也可以在ildasm.exe中看到一些内容,只需删除obj\Release和bin\Release目录中的.pdb文件,它现在看起来如下所示:

代码语言:javascript
复制
.method private hidebysig static void  Main(string[] args) cil managed
{
  .entrypoint
  // Code size       50 (0x32)
  .maxstack  2
  .locals init (int32 V_0,
           int32 V_1,
           int32 V_2)
  IL_0000:  ldc.i4.1
  // etc...

V_0V_1等名字当然不是很好,反汇编程序通常会想出更好的方法。有点像“数字”。

所以,很清楚ILSpy中的bug在哪里,它也读取PDB文件,但是错误地显示了它检索到的符号。您可以将该错误提交给供应商,但是他们不太可能将其视为一个高优先级的bug。

票数 5
EN

Stack Overflow用户

发布于 2014-09-05 18:34:44

这可能是反编译的一些问题。因为IL在.NET 4.5 VS2013上是正确的:

代码语言:javascript
复制
.entrypoint
  // Code size       79 (0x4f)
  .maxstack  2
  .locals init ([0] int32 test_1,
           [1] int32 test_2,
           [2] int32 test_3,
           [3] bool CS$4$0000)
  IL_0000:  nop
  IL_0001:  ldc.i4.1
  IL_0002:  stloc.0

编辑:--它使用.pdb文件中的数据(参见这个答案)来获得正确的名称变量。如果没有pdb,它将有形式V_0, V_1, V_2中的变量。

编辑:

方法中的文件NameVariables.cs中的变量名称损坏:

代码语言:javascript
复制
public string GetAlternativeName(string oldVariableName)
{
    if (oldVariableName.Length == 1 && oldVariableName[0] >= 'i' && oldVariableName[0] <= maxLoopVariableName) {
        for (char c = 'i'; c <= maxLoopVariableName; c++) {
            if (!typeNames.ContainsKey(c.ToString())) {
                typeNames.Add(c.ToString(), 1);
                return c.ToString();
            }
        }
    }

    int number;
    string nameWithoutDigits = SplitName(oldVariableName, out number);

    if (!typeNames.ContainsKey(nameWithoutDigits)) {
        typeNames.Add(nameWithoutDigits, number - 1);
    }

    int count = ++typeNames[nameWithoutDigits];

    if (count != 1) {
        return nameWithoutDigits + count.ToString();
    } else {
        return nameWithoutDigits;
    }
}

NameVariables类使用this.typeNames字典来存储变量的名称,而不带尾号(这些变量对ILSpy来说意味着一些特殊的东西,甚至对IL也有特殊意义,但实际上我对此表示怀疑),它们在反编译方法中的表象与计数器相关联。

这意味着所有变量(test_1, test_2, test_3)将以一个槽("test_")结尾,对于第一个变量,count var将为一个,因此执行:

代码语言:javascript
复制
else {
    return nameWithoutDigits;
}

其中nameWithoutDigitstest_

编辑

首先,感谢@HansPassant及其回答指出了这篇文章中的错误。

因此,问题的根源是:

ILSpy和ildasm一样聪明,因为它还使用.pdb数据(或者它是如何获得test_1, test_2名称的)。但是,它的内部工作方式是经过优化的,可以与程序集一起使用,而不需要任何调试相关信息,因此,与处理V_0, V_1, V_2变量有关的优化与来自.pdb文件的大量元数据不一致。

据我所知,罪魁祸首是将_0从单个变量中删除的优化。

修复它可能需要将.pdb数据使用的事实传播到变量名称代代代码中。

票数 15
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/25691865

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档