Компилятор С# умнее компилятора VB.NET?

Если я посмотрю на IL, созданный в Linqpad для двух следующих фрагментов кода, мне интересно, что здесь происходит.

In c#

int i = 42;

приводит к следующему коду IL

IL_0000:  ret

тогда как в ВБ

Dim i As Integer = 42

it is

IL_0000:  ldc.i4.s    2A 
IL_0002:  stloc.0  

По-видимому, компилятор С# понимает, что значение никогда не используется, и поэтому просто ничего не возвращает. В VB.NET переводится фактический код.

Это связано с различиями в оптимизации компилятора или есть что-то еще?

Обновление: Просто чтобы прояснить это - я просто ввожу эту строку в LinqPad и смотрю на создаваемый IL (скорее всего, запустив соответствующий компилятор). Программы нет.


person Olaf    schedule 09.02.2012    source источник
comment
Я считаю, что компилятор C# в настоящее время выполняет больше оптимизаций (это почти наверняка изменится, когда появится Roslyn). Но в этом случае это немного ложная победа для компилятора C #, поскольку он все равно почти наверняка будет оптимизирован компилятором JIT.   -  person Damien_The_Unbeliever    schedule 09.02.2012
comment
@AakashM: Когда я пишу, это все, что я ввожу в LinqPad. Другого кода нет. LinqPad создает IL путем компиляции в фоновом режиме.   -  person Olaf    schedule 09.02.2012
comment
Компилируется ли он в то же самое в С# при отладке? Я предполагаю, что C# оптимизирует больше, когда находится в режиме выпуска, чем VB.NET. Это одна из причин, по которой вы не можете оценивать переменные в выпуске на C#, которые не используются, в то время как вы можете это делать в VB.NET. Я предпочитаю последнее.   -  person Tim Schmelter    schedule 09.02.2012
comment
@Tim: я вообще не компилирую - это просто результат LinqPad IL.   -  person Olaf    schedule 09.02.2012
comment
LINQPad вызывает CodeDomProviders для C# и VB, которые подключаются к компиляторам CSC.exe и VB. Отсюда и верность переводов IL. Вы можете включить/отключить оптимизацию компиляторов в Edit | Настройки (или с помощью кнопки в строке состояния в последних бета-версиях).   -  person Joe Albahari    schedule 09.02.2012
comment
@Joe: Действительно, когда запросы Optimize переведены в false, код IL остается прежним. Заставляет меня задаться вопросом, как эти запросы оптимизированы (это просто переключатель /optimize?). И все же, как доказал AakashM, даже ассемблерный код отличается.   -  person Olaf    schedule 09.02.2012


Ответы (2)


Отбросив вопрос о linqpad, я запустил vbc и csc с /optimize+ /debug- в этих программах:

Module f

Public Sub Main()
    Dim i As Integer = 42
End Sub

End Module

и

public static class f
{

public static void Main()
{
    int i = 42;
}

}

и получил эти результаты CIL от ILDASM:

Для ВБ:

.method public static void  Main() cil managed
{
  .entrypoint
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor() = ( 01 00 00 00 ) 
  // Code size       4 (0x4)
  .maxstack  1
  .locals init (int32 V_0)
  IL_0000:  ldc.i4.s   42
  IL_0002:  stloc.0
  IL_0003:  ret
} // end of method f::Main

Для С#:

.method public hidebysig static void  Main() cil managed
{
  .entrypoint
  // Code size       1 (0x1)
  .maxstack  8
  IL_0000:  ret
} // end of method f::Main

Итак, да, по крайней мере в этом отношении csc "умнее" vbc. Но я уверен, что JITter удалит любую разницу во время выполнения.

изменить

Я проверил, и на самом деле исполняемый нативный код другой, по крайней мере, в моей системе. Я вставил Console.ReadLine() вызовов в оба, чтобы дать мне возможность подключить отладчик, и я получил следующие дизассемблированные версии:

Из ВБ:

00000000  sub         rsp,38h 
00000004  mov         dword ptr [rsp+20h],0 
0000000c  mov         rax,7FF000434D8h 
00000016  mov         eax,dword ptr [rax] 
00000018  test        eax,eax 
0000001a  je          0000000000000021 
0000001c  call        FFFFFFFFE45BA230 
00000021  mov         dword ptr [rsp+20h],2Ah 
00000029  call        FFFFFFFFE26ABF20 
0000002e  mov         qword ptr [rsp+28h],rax 
00000033  nop 
00000034  jmp         0000000000000036 
00000036  add         rsp,38h 
0000003a  ret 

Из С#:

00000000  sub         rsp,38h 
00000004  mov         rax,7FF000534D8h 
0000000e  mov         eax,dword ptr [rax] 
00000010  test        eax,eax 
00000012  je          0000000000000019 
00000014  call        FFFFFFFFE45AA230 
00000019  call        FFFFFFFFE391BF20 
0000001e  mov         qword ptr [rsp+20h],rax 
00000023  nop 
00000024  jmp         0000000000000026 
00000026  add         rsp,38h 
0000002a  ret 

Моей сборки почти не существует, но даже я это вижу

mov         dword ptr [rsp+20h],2Ah 

в from-VB относится к постоянному шестнадцатеричному значению 2A, которое равно десятичному числу 42. Итак, в конце концов он действительно выполняет дополнительные инструкции.

person AakashM    schedule 09.02.2012
comment
ну, у нас также есть больший стек, как в 8 (C #) против 1 - person V4Vendetta; 09.02.2012

Я думаю, что в случае C # компилятор выполняет часть выделения памяти и сохраняет значение int за один шаг, а в случае VB оператор DIM является первым шагом, который просто выделяет память, а затем значение сохраняется на втором шаге. DIM является универсальным и используется со всеми типами данных, поэтому во всех случаях это может быть что-то вроде дополнительного шага. Мысли?

person Mujtaba Hassan    schedule 09.02.2012