我曾经是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;
但结果仍然相同。 还存在两个跳转指令。 如果有更多信息,我将不胜感激。
答案 0 :(得分:11)
您没有使用优化进行编译 - nop
指令指示了这一点(编译器插入这些指令以用作锚点,以便您可以在括号上放置断点)。
即使您选中了“优化代码”复选框,Visual Studio也不会始终生成优化代码。通常,当您在调试器中启动时,它将禁用优化,以便调试会话的行为更符合您的预期。
此外,你不是在比较苹果和苹果,因为苹果占了很多。
string[].Length
是C#中的属性,不是公共变量,而且不是局部变量。通常通过使用代码将属性视为公共变量,但实际上可以作为完整的get / set方法存在。编译器必须发出代码来处理这个问题,尤其是在单独的程序集中定义属性时。
尝试使用本地int
变量的示例,并打开编译器优化(使用优化构建,启动程序,启动后附加调试器,查看反汇编)。
答案 1 :(得分:4)
您正在查看该程序的Debug版本。切换到发布版本。
并且您必须更改选项,以便在使用调试器查看反汇编时,优化器不会被禁用。工具+选项,调试,常规,取消"抑制模块负载的JIT优化"选项。
您现在可以看到更紧凑的代码。 x86抖动确实执行分支消除并使用AGU进行数学运算,你可以看到它在this answer中完成,而不是在这里。如果您期望与C或C ++编译器的优化器完全相同,那么您将会感到失望,抖动优化器在非常严格的时间限制下运行,因为它在运行时运行。您将在this answer中找到它执行的优化大纲。