Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/csharp/322.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/reactjs/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
发布和调试之间的不同C#输出_C#_Debugging_Release_Language Lawyer - Fatal编程技术网

发布和调试之间的不同C#输出

发布和调试之间的不同C#输出,c#,debugging,release,language-lawyer,C#,Debugging,Release,Language Lawyer,我这里有一个小C#程序,它在调试版本和发布版本之间产生不同的输出。我认为,发布版本的空输出与C语言规范是一致的。此程序不应产生输出,但调试版本会产生输出 我从命令行(在VS环境之外)运行了发行版和调试版,得到了相同的不一致输出。我已经反编译了调试版本(使用ILDASM),然后用ILASM重新编译。当我这样做时,新编译的程序的行为就像发布版本一样。我只能想象,当我反编译然后重新编译时,有些东西被遗漏了,但我无法确定有什么不同 关于EXE文件大小:VS生成的发行版和调试版的文件大小相同:5120字节

我这里有一个小C#程序,它在调试版本和发布版本之间产生不同的输出。我认为,发布版本的空输出与C语言规范是一致的。此程序不应产生输出,但调试版本会产生输出

我从命令行(在VS环境之外)运行了发行版和调试版,得到了相同的不一致输出。我已经反编译了调试版本(使用ILDASM),然后用ILASM重新编译。当我这样做时,新编译的程序的行为就像发布版本一样。我只能想象,当我反编译然后重新编译时,有些东西被遗漏了,但我无法确定有什么不同

关于EXE文件大小:VS生成的发行版和调试版的文件大小相同:5120字节。当我反编译和重新编译时,两个版本的文件大小相同,但更小:3072

这个程序非常小,我已经看过反射器中的IL,我看不到任何会导致输出差异的东西

有人(希望详细)解释了为什么会有差异吗

请注意,我并没有试图使调试版本和发布版本保持一致,我想了解为什么它们不一致

回想一下我上面所说的——调试版本和发布版本即使在从命令行运行时也会产生不同的输出。如果您告诉我运行时正在对发布版本进行某种优化,而不是对调试版本进行优化,那么调试/发布版本程序集中一定嵌入了某种东西,告诉运行时打开/关闭优化。嵌入的“某物”是什么?为什么在使用ILDASM/ILASM时它不会继续

代码如下:

using System;

class Test {
    static int value = 0;
    static int a = Initialize("Assigning a");
    static int b = Initialize("Assigning b");
    static String name = "Fred";
    static int c = Initialize("Assigning c");

    static int Initialize(String mssg) {
        ++value;
        Console.WriteLine("In Initialize() :: {0}, name={1}, returning {2}", mssg, name, value);
        return value;
    } // Initialize()

    static void Main() {
    } // Main()
} // class Test
下面是Visual Studio生成的调试版本的输出:

In Initialize() :: Assigning a, name=, returning 1
In Initialize() :: Assigning b, name=, returning 2
In Initialize() :: Assigning c, name=Fred, returning 3

运行发布版本不会生成任何输出。

您实际上没有在应用程序(Main内部)的任何位置使用变量a、b或c,因此我假设它们正在被优化。当我在关闭优化的情况下在LinqPad中运行该代码时,它会显示您描述的输出,而在打开优化的情况下,它只显示Main()正在执行。如果我更新Main()中的代码以引用这些变量中的一个,则输出与优化外建一致。

直到需要时才调用静态类初始值设定项。显然,调试版本和发布版本在需要时的决定是不同的。特别是我的猜测是,发布版本完全优化了主版本,因此从未加载该类。它似乎已经决定,因为main什么都不做,所以它可以优化所有东西-在这种情况下,这似乎是一个错误的决定

打开优化(释放模式)会影响生成的IL,以及抖动的行为

您可能看到抖动消除了未使用变量的初始化

这解释了ILDASM/ILASM行为,以及IL之间没有显著差异的事实


我怀疑这种行为是由CLR头中某个地方的标志值控制的。。参见

经过更多的研究,我找到了我想要的答案(感谢Blogbeard为我指明了正确的方向)

事实证明,当您编译以进行调试时,生成的程序集在默认情况下由“调试模式”为的DebuggableAttribute修饰

显然,正是这些标志的组合似乎关闭了JIT优化,导致了我在程序调试版本中看到的输出。程序的发布版本有不同的“调试模式”,允许JIT优化继续进行

当然,如果为调试生成在AssemblyInfo中手动设置DebuggableAttribute(就像我在测试期间所做的那样),则可以覆盖默认行为


我确信有一些CLR/JIT律师可以提供更详细的解释。

最有可能的是,在发布模式下,测试类未加载,因为没有对它的引用。尝试添加
Console.WriteLine(Test.name)Console.WriteLine(“在main中”)以显示实际上正在调用main。(我刚刚试过,您仍然可以得到不同的输出,但是如果您做得更多,例如
Console.WriteLine(“在Main():{0}”,name);
,然后调试并释放,开始表现相同)分页skeet先生,skeet先生如果您愿意,请来到SO桌面,我发现了如何禁用调试优化,以便您仍然可以在调试器中看到不同的行为(如果您选中“启用地址级别ebugging”复选框,您可以从Disassemby窗口中看到汇编代码)。我知道发生了什么(JITed代码不调用其他静态方法),但我不知道为什么会发生这种情况,所以我不打算发布一个答案,只是猜测将在不调用静态函数的情况下打印。所以主要的并没有被完全淘汰,所以我明白了。我想只是取消了未使用变量的初始化。“特别是我的猜测是,发布版本完全优化了main out,因此从未加载该类。”事实并非如此,put
Console.WriteLine(“IN main()”)在main中,您仍然会得到相同的行为,但它将打印“in main()”
DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.Default