Условные переходы
From Wiki.conus.info
Об условных переходах.
void f_signed (int a, int b) { if (a>b) printf ("a>b\n"); if (a==b) printf ("a==b\n"); if (a<b) printf ("a<b\n"); }; void f_unsigned (unsigned int a, unsigned int b) { if (a>b) printf ("a>b\n"); if (a==b) printf ("a==b\n"); if (a<b) printf ("a<b\n"); }; int main() { f_signed(1, 2); f_unsigned(1, 2); return 0; };
Имеем в итоге функцию f_signed():
_a$ = 8 ; size = 4 _b$ = 12 ; size = 4 _f_signed PROC ; File c:\...\1.c ; Line 2 push ebp mov ebp, esp ; Line 3 mov eax, DWORD PTR _a$[ebp] cmp eax, DWORD PTR _b$[ebp] jle SHORT $LN3@f_signed ; Line 4 push OFFSET $SG737 ; 'a>b', 0aH, 00H call _printf add esp, 4 $LN3@f_signed: ; Line 5 mov ecx, DWORD PTR _a$[ebp] cmp ecx, DWORD PTR _b$[ebp] jne SHORT $LN2@f_signed ; Line 6 push OFFSET $SG739 ; 'a==b', 0aH, 00H call _printf add esp, 4 $LN2@f_signed: ; Line 7 mov edx, DWORD PTR _a$[ebp] cmp edx, DWORD PTR _b$[ebp] jge SHORT $LN4@f_signed ; Line 8 push OFFSET $SG741 ; 'a<b', 0aH, 00H call _printf add esp, 4 $LN4@f_signed: ; Line 9 pop ebp ret 0 _f_signed ENDP
Первая инструкция JLE значит Jump if Larger or Equal. То есть, если второй операнд больше первого или равен ему, произойдет переход туда, где будет следующая проверка.
А если это условие не срабатывает, то есть второй операнд меньше первого, то перехода не будет, и сработает первый printf().
Вторая проверка это JNE: Jump if Not Equal. Переход не произойдет, если операнды равны.
Третья проверка JGE: Jump if Greater or Equal - переход если второй операнд больше первого или равен ему.
Кстати, если все три условных перехода сработают, ни один printf() не вызовется. Но, без внешнего вмешательства, это, пожалуй, невозможно.
GCC 4.4.1 производит почти такой же код, за исключением puts() вместо printf().
Далее функция f_unsigned():
.globl f_unsigned .type f_unsigned, @function f_unsigned: push ebp mov ebp, esp sub esp, 24 mov eax, DWORD PTR [ebp+8] cmp eax, DWORD PTR [ebp+12] jbe .L7 mov DWORD PTR [esp], OFFSET FLAT:.LC0 ; "a>b" call puts .L7: mov eax, DWORD PTR [ebp+8] cmp eax, DWORD PTR [ebp+12] jne .L8 mov DWORD PTR [esp], OFFSET FLAT:.LC1 ; "a==b" call puts .L8: mov eax, DWORD PTR [ebp+8] cmp eax, DWORD PTR [ebp+12] jae .L10 mov DWORD PTR [esp], OFFSET FLAT:.LC2 ; "a<b" call puts .L10: leave ret
Здесь все то же самое, только инструкции условных переходов немного другие: JBE - Jump if Below or Equal и JAE - Jump if Above or Equal.
Эти инструкции отличаются от JG/JGE/JL/JLE тем, что работают с беззнаковыми переменными.
Отступление: signed number representations.
Таким образом, увидев где используется JG/JL вместо JA/JB и наоборот, можно сказать почти уверенно насчет того, является ли тип переменной знаковым (signed) или беззнаковым (unsigned).
GCC 4.4.1 производит почти такой же код, за исключением puts() вместо printf().
Далее функция main(), где ничего нового нет:
main: push ebp mov ebp, esp and esp, -16 sub esp, 16 mov DWORD PTR [esp+4], 2 mov DWORD PTR [esp], 1 call f_signed mov DWORD PTR [esp+4], 2 mov DWORD PTR [esp], 1 call f_unsigned mov eax, 0 leave ret