2012-09-22 3 views
2

У меня есть следующие функции:Анализ MSIL код генерируется из C#

public string MyPhrase(int val) 
{ 
    if ((val %3 == 0) && (val % 6 == 0)) 
     return "Fizz Bang"; 
    if (val % 3 == 0) 
     return "Fizz"; 
    if (val % 6 == 0) 
     return "Bang"; 
    return ""; 
} 

После компиляции этого и просмотра его с ILDASM, я получаю этот выход:

IL_0000: ldarg.1 
IL_0001: ldc.i4.3 
IL_0002: rem 
IL_0003: brtrue.s IL_0010 

IL_0005: ldarg.1 
IL_0006: ldc.i4.6 
IL_0007: rem 
IL_0008: brtrue.s IL_0010 

IL_000a: ldstr  "Fizz Bang" 
IL_000f: ret 

IL_0010: ldarg.1 
IL_0011: ldc.i4.3 
IL_0012: rem 
IL_0013: brtrue.s IL_001b 

IL_0015: ldstr  "Fizz" 
IL_001a: ret 

IL_001b: ldarg.1 
IL_001c: ldc.i4.6 
IL_001d: rem 
IL_001e: brtrue.s IL_0026 

IL_0020: ldstr  "Bang" 
IL_0025: ret 

IL_0026: ldstr  "" 
IL_002b: ret 

Глядя на this page, brtrue будет если true. Меня смущает линия IL_0003. Он говорит, что он должен перейти к строке IL_0010, если это правда. В моем коде C#, хотя, я использую && для сравнения двух выражений, прежде чем мой поток программы должен перейти к следующему if. Это кажется обратным. Из опубликованного кода MSIL кажется, что он проверяет, действительно ли моя операция верна, и если это так, ее переход к моему следующему блоку if, что было бы логически неверным. Может кто-нибудь объяснить, что мне не хватает?

+0

Интересно, почему вы выбрали этот пример. Не то, чтобы компилятор это понял, но «взрыва» никогда нельзя было вернуть, не так ли? Если 'val' были делятся на' 6', то наверняка он был бы делимым на '3'? –

+1

@JeppeStigNielsen Действительно. Вот почему традиционно проблема FizzBang использует 3 и 5, а не 3 и 6. – verdesmarald

+0

@JeppeStigNielsen - Фактическая функция вообще не полезна. Я просто анализировал код MSIL для удовольствия. – Icemanind

ответ

4

Это побочный эффект оценки короткого замыкания для Оператор & &. Что обещает, что правое выражение оператора не будет оценено, если левая сторона ложна. Таким образом, вы видите, что он пропускает выражение val% 6 == 0 и возвращает выражение «Fizz Bang», если код операции REM возвращает ненулевой результат.

+0

Да, «истина» означает «ненулевое» в этом мире, а ОП сравнивается с «0». –

0

Это Блок нагрузка аргументов данные из стека, прежде, чем начать сравнение

Так это нормально, чтобы перейти на этот раздел загрузки данных

IL_0010: ldarg.1 
IL_0011: ldc.i4.3 
... 
1

brtrue.s передает управление заданной цели, если значение в стеке отличное от нуля.

поэтому, в вашем IL код IL_0003 является переходом на IL_0010. означает (val% 3 == 0) условие return false. Вы использовали && в первой, если условие if ((val %3 == 0) && (val % 6 == 0)) так, на первое условие (val % 3 == 0) возвращение ложным, второе условие не будет проверять

IL_0005: ldarg.1 
IL_0006: ldc.i4.6 
IL_0007: rem 
IL_0008: brtrue.s IL_0010 

и контроль передачи в IL_0010

IL_0010: ldarg.1 
IL_0011: ldc.i4.3 
IL_0012: rem 
IL_0013: brtrue.s IL_001b 

проверить это для получения дополнительной информации: http://weblogs.asp.net/kennykerr/archive/2004/09/23/introduction-to-msil-part-6-common-language-constructs.aspx

Смежные вопросы