Условные переходы

From Wiki.conus.info

Jump to: navigation, search

Об условных переходах.

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
Personal tools
Namespaces
Variants
Actions
Navigation
Toolbox