C#vs C ++三元运算符

时间:2013-12-29 16:06:57

标签: c# c++ ternary-operator

我曾经是Windows上的C ++程序员。 我知道编译器会优化C ++中的三元运算符。

C ++代码:

#include "stdafx.h"
int _tmain(int argc, _TCHAR* argv[])
{
    int result = argc > 3 ? 1 : 5;
    printf("%d", result);
    return 0;
}

由于管道内容,生成的本机代码如下所示(当然发布模型):

int result = argc > 3 ? 1 : 5;
00B21003  xor         eax,eax  
00B21005  cmp         dword ptr [argc],3
00B21009  setle       al  
00B2100C  lea         eax,[eax*4+1]

C#代码:

namespace TernaryOperatorCSharp
{
    static void Main(string[] args)
    {
        int argc = args.Length;
        int result = argc > 1 ? 2 : 5;
        System.Console.WriteLine(result);
    }
}

我查找了生成的本机代码JIT,但根本没有优化(仍然是两个跳转指令)。

int result = argc > 1 ? 2 : 5;
0000002f  cmp         dword ptr [ebp-4],1 
00000033  jg          0000003F 
00000035  nop 
00000036  mov         dword ptr [ebp-0Ch],5 
0000003d  jmp         00000046 
0000003f  mov         dword ptr [ebp-0Ch],2 
00000046  mov         eax,dword ptr [ebp-0Ch] 
00000049  mov         dword ptr [ebp-8],eax 
System.Console.WriteLine(result);
0000004c  mov         ecx,dword ptr [ebp-8] 
0000004f  call        6A423CBC 

为什么C#JIT编译器不能像C ++编译器那样进行相同的优化?

这背后的故事是什么?

任何信息都将受到赞赏。


你好, 我修改了C#程序并使用发布模型运行它。

之前

int result = args.Length > 1 ? 2 : 5;

立即

int argc = args.Length;
int result = argc > 1 ? 2 : 5;

但结果仍然相同。 还存在两个跳转指令。 如果有更多信息,我将不胜感激。

2 个答案:

答案 0 :(得分:11)

您没有使用优化进行编译 - nop指令指示了这一点(编译器插入这些指令以用作锚点,以便您可以在括号上放置断点)。

即使您选中了“优化代码”复选框,Visual Studio也不会始终生成优化代码。通常,当您在调试器中启动时,它将禁用优化,以便调试会话的行为更符合您的预期。

此外,你不是在比较苹果和苹果,因为苹果占了很多。

string[].Length是C#中的属性,不是公共变量,而且不是局部变量。通常通过使用代码将属性视为公共变量,但实际上可以作为完整的get / set方法存在。编译器必须发出代码来处理这个问题,尤其是在单独的程序集中定义属性时。

尝试使用本地int变量的示例,并打开编译器优化(使用优化构建,启动程序,启动后附加调试器,查看反汇编)。

答案 1 :(得分:4)

您正在查看该程序的Debug版本。切换到发布版本。

并且您必须更改选项,以便在使用调试器查看反汇编时,优化器不会被禁用。工具+选项,调试,常规,取消"抑制模块负载的JIT优化"选项。

您现在可以看到更紧凑的代码。 x86抖动确实执行分支消除并使用AGU进行数学运算,你可以看到它在this answer中完成,而不是在这里。如果您期望与C或C ++编译器的优化器完全相同,那么您将会感到失望,抖动优化器在非常严格的时间限制下运行,因为它在运行时运行。您将在this answer中找到它执行的优化大纲。