Подтвердить что ты не робот

С# vs С++ тернарный оператор

Раньше я был программистом на С++ в Windows. Я знаю, что компилятор оптимизирует тройной оператор в С++.

Код С++:

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

Из-за материала конвейера сгенерированный собственный код показан ниже (конечно Release):

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]

Код С#:

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 

Почему компилятор С# JIT не делает ту же оптимизацию, что и компилятор С++?

Какая история за этим?

Любая информация будет оценена.


Привет, Я изменил программу С# и запустил ее с помощью модели выпуска.

До

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

Теперь

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

Но результат все тот же. Существует еще две инструкции перехода. Я буду признателен, если будет дополнительная информация.

4b9b3361

Ответ 1

Вы не компилируете с оптимизацией - инструкция nop указывает на это (компилятор вставляет их для использования в качестве якорей, чтобы вы могли установить точку останова на скобе).

Visual Studio не всегда будет создавать оптимизированный код, даже если вы установите флажок "оптимизировать код". Часто, когда вы запускаете в отладчике, он все равно отключает оптимизацию, так что сеанс отладки будет вести себя как и следовало ожидать.

Кроме того, вы не сравниваете яблоки с яблоками, на которые приходится гораздо больше крутизны.

string[].Length является свойством в С#, а не общедоступной переменной и, кроме того, не локальной переменной. Свойства часто обрабатываются как общедоступные переменные, потребляя код, но на самом деле могут существовать как полномасштабные методы get/set. Компилятор должен испускать код для его обработки, особенно если свойство определено в отдельной сборке.

Попробуйте пример с локальной переменной int, а с включенной оптимизацией компилятора (с оптимизацией, запуском программы, подключением отладчика после запуска, разборкой просмотра).

Ответ 2

Вы смотрите на сборку Debug программы. Перейдите к сборке Release.

И вам придется изменить параметр, чтобы оптимизатор не отключился, когда вы используете отладчик, чтобы посмотреть на разборку. Tools + Options, Debugging, General, отключите опцию "Подавлять оптимизацию JIT при загрузке модуля".

Теперь вы увидите более компактный код. Джиттер x86 выполняет исключение ветвления и использует AGU для математики, вы можете видеть, что это делается в этом ответе, просто не здесь. Вы будете разочарованы, если вы ожидаете точной четности с оптимизатором компилятора C или С++, оптимизатор джиттера работает с довольно строгими временными ограничениями, поскольку он работает во время выполнения. Вы найдете схему оптимизации, которую он выполняет в этом ответе.