Delphi-条件判断那些事


之前照着天书夜读,用Delphi来弄了下循环体,现在就来弄一下条件判断吧.
首先肯定是我们经常看见的IF语句咯.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Var
I: Integer;

Begin
I:= 99;
If (I> 0)And (I< 0) Then
Writeln('I>0')
Else
If (I> 10)And (I< 100) Then
Writeln('I>10 and I<100')
Else
Writeln('I>100');

End.

反汇编出来会是什么样子的呢?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
Project5.dpr.12: I:= 99;
004AC44C B863000000 mov eax,$00000063
Project5.dpr.13: If (I> 0)And (I< 0) Then
004AC451 85C0 test eax,eax
004AC453 7E1F jle $004ac474
004AC455 85C0 test eax,eax
004AC457 7D1B jnl $004ac474
Project5.dpr.14: Writeln('I>0')
004AC459 A1DC314B00 mov eax,[$004b31dc]
004AC45E BAC4C44A00 mov edx,$004ac4c4
004AC463 E874BAF5FF call @Write0UString
004AC468 E8BF89F5FF call @WriteLn
004AC46D E83E7FF5FF call @_IOTest
004AC472 EB3E jmp $004ac4b2
Project5.dpr.16: If (I> 10)And (I< 100) Then
004AC474 83F80A cmp eax,$0a
004AC477 7E20 jle $004ac499
004AC479 83F864 cmp eax,$64
004AC47C 7D1B jnl $004ac499
Project5.dpr.17: Writeln('I>10 and I<100')
004AC47E A1DC314B00 mov eax,[$004b31dc]
004AC483 BAD8C44A00 mov edx,$004ac4d8
004AC488 E84FBAF5FF call @Write0UString
004AC48D E89A89F5FF call @WriteLn
004AC492 E8197FF5FF call @_IOTest
004AC497 EB19 jmp $004ac4b2
Project5.dpr.19: Writeln('I>100');
004AC499 A1DC314B00 mov eax,[$004b31dc]
004AC49E BA04C54A00 mov edx,$004ac504
004AC4A3 E834BAF5FF call @Write0UString
004AC4A8 E87F89F5FF call @WriteLn
004AC4AD E8FE7EF5FF call @_IOTest

我们这里就容易得出来Delphi里面IF语句的结构了.
判断1
不满足就跳————————-|
满足条件代码 |
[无条件Jmp到所有判断外] |
[判断2] <——|
………………………………………..
就是这样的
在IF的反汇编上面 和 书中的VC反汇编出来的代码差不多.
接下来就是看switch语句(Delphi里面的Case):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
Var
I: Integer;
Begin
I:= 9;
Case I Of
0:
Writeln('0');
1:
Writeln('1');
2:
Writeln('2');
3:
Writeln('3');
4:
Writeln('4');
5:
Writeln('5');
6:
Writeln('6');
7:
Writeln('7');
Else
Writeln('0');
End;
End.

反汇编一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
Project5.dpr.12: I:= 9;
004AC44C B809000000 mov eax,$00000009
Project5.dpr.13: Case I Of
004AC451 83F807 cmp eax,$07
004AC454 0F8703010000 jnbe $004ac55d
004AC45A FF248561C44A00 jmp dword ptr [eax*4+$4ac461]
004AC461 81C44A009EC4 add esp,$c49e004a
004AC467 4A dec edx
004AC468 00BBC44A00D8 add [ebx-$27ffb53c],bh
004AC46E C44A00 les ecx,[edx+$00]
004AC471 F5 cmc
004AC472 C44A00 les ecx,[edx+$00]
004AC475 0FC54A0029 pextrw ecx,qword ptr [edx+$00],$29
004AC47A C54A00 lds ecx,[edx+$00]
004AC47D 43 inc ebx
004AC47E C54A00 lds ecx,[edx+$00]
Project5.dpr.15: Writeln('0');
004AC481 A1DC314B00 mov eax,[$004b31dc]
004AC486 66BA3000 mov dx,$0030
004AC48A E8DDADF5FF call @Write0WChar
004AC48F E89889F5FF call @WriteLn
004AC494 E8177FF5FF call @_IOTest
004AC499 E9D7000000 jmp $004ac575
Project5.dpr.17: Writeln('1');
004AC49E A1DC314B00 mov eax,[$004b31dc]
004AC4A3 66BA3100 mov dx,$0031
004AC4A7 E8C0ADF5FF call @Write0WChar
004AC4AC E87B89F5FF call @WriteLn
004AC4B1 E8FA7EF5FF call @_IOTest
004AC4B6 E9BA000000 jmp $004ac575
Project5.dpr.19: Writeln('2');
004AC4BB A1DC314B00 mov eax,[$004b31dc]
004AC4C0 66BA3200 mov dx,$0032
004AC4C4 E8A3ADF5FF call @Write0WChar
004AC4C9 E85E89F5FF call @WriteLn
004AC4CE E8DD7EF5FF call @_IOTest
004AC4D3 E99D000000 jmp $004ac575
Project5.dpr.21: Writeln('3');
004AC4D8 A1DC314B00 mov eax,[$004b31dc]
004AC4DD 66BA3300 mov dx,$0033
004AC4E1 E886ADF5FF call @Write0WChar
004AC4E6 E84189F5FF call @WriteLn
004AC4EB E8C07EF5FF call @_IOTest
004AC4F0 E980000000 jmp $004ac575
Project5.dpr.23: Writeln('4');
004AC4F5 A1DC314B00 mov eax,[$004b31dc]
004AC4FA 66BA3400 mov dx,$0034
004AC4FE E869ADF5FF call @Write0WChar
004AC503 E82489F5FF call @WriteLn
004AC508 E8A37EF5FF call @_IOTest
004AC50D EB66 jmp $004ac575
Project5.dpr.25: Writeln('5');
004AC50F A1DC314B00 mov eax,[$004b31dc]
004AC514 66BA3500 mov dx,$0035
004AC518 E84FADF5FF call @Write0WChar
004AC51D E80A89F5FF call @WriteLn
004AC522 E8897EF5FF call @_IOTest
004AC527 EB4C jmp $004ac575
Project5.dpr.27: Writeln('6');
004AC529 A1DC314B00 mov eax,[$004b31dc]
004AC52E 66BA3600 mov dx,$0036
004AC532 E835ADF5FF call @Write0WChar
004AC537 E8F088F5FF call @WriteLn
004AC53C E86F7EF5FF call @_IOTest
004AC541 EB32 jmp $004ac575
Project5.dpr.29: Writeln('7');
004AC543 A1DC314B00 mov eax,[$004b31dc]
004AC548 66BA3700 mov dx,$0037
004AC54C E81BADF5FF call @Write0WChar
004AC551 E8D688F5FF call @WriteLn
004AC556 E8557EF5FF call @_IOTest
004AC55B EB18 jmp $004ac575
Project5.dpr.31: Writeln('0');
004AC55D A1DC314B00 mov eax,[$004b31dc]
004AC562 66BA3000 mov dx,$0030
004AC566 E801ADF5FF call @Write0WChar
004AC56B E8BC88F5FF call @WriteLn
004AC570 E83B7EF5FF call @_IOTest

在这里我们看到了一个Delphi的优化,它首先把I和7比,如果大于就直接跳到else语句那里.
如果小于等于,我们看到是无条件Jmp到一个I为等间距偏移的地方,也就是每个writeln语句是等大小的.
要是我们改成不是01234567呢?大家自己试一下,不是等距case代码还是没有变.
而VC里面会怎么样?
cmp->je->cmp->je->cmp->je
就是这样不停的对比,如果相等就跳.这样符合我们思维一些.
转自https://www.cnblogs.com/huangjacky/archive/2010/02/04/1663847.html

For循环

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Function TestFor( a, b: Integer ): Integer ;
Var
I: Integer ;
Begin
Result := a + b ;
For I := 0 To 49 Do
Result := Result + I ;
End ;
{$R *.dfm}

Procedure TForm1.btn1Click( Sender: TObject ) ;
Begin
ShowMessage( IntToStr( TestFor( 1, 2 ) ) ) ;
End ;

反汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
Unit4.pas.28: Result := a + b ;
00523AE0 03D0 add edx,eax //执行a+b,但是我很奇怪为什么不用add eax,edx 这样最后就不用执行那句mov eax,edx了,节约一句
Unit4.pas.29: For I := 0 To 49 Do
00523AE2 33C0 xor eax,eax //清除eax,来充当I这个循环变量
Unit4.pas.30: Result := Result + I ;
00523AE4 03D0 add edx,eax //累计和,并把循环变量+1,这里就是循环体的执行代码
00523AE6 40 inc eax
Unit4.pas.29: For I := 0 To 49 Do
00523AE7 83F832 cmp eax,$32 //边界比较,不等于就跳回去,继续执行循环体代码.
00523AEA 75F8 jnz $00523ae4 //看来还是再写个函数来看看
Unit4.pas.31: End ;
00523AEC 8BC2 mov eax,edx
00523AEE C3 ret

对比书中C的反汇编代码,Delphi反汇编出来的代码很精简,虽然声明了局部变量,但是函数直接用寄存器代替了.很好.
书中C循环体先直接用Jmp跳过去与临界变量比较,然后再来看是否执行循环体,而改变循环变量它用了add eax,1,然后再把eax传给栈上面的I.
后来我尝试改成0 to -1 Delphi编译器会识别出来,然后不会添加任何循环代码到函数中去的.

接下来是do循环,也就是Repeat

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
function TestRepeat(a,b:Integer):Integer ;
var
I:Integer;
begin
Result:=a + b;
I:=0;
repeat
Result:= Result + I;
Inc(I);
until I = 50;
end;
反汇编代码:
``` asm
Unit4.pas.30: Result:=a + b;
00523AE0 03D0 add edx,eax
Unit4.pas.31: I:=0;
00523AE2 33C0 xor eax,eax
Unit4.pas.33: Result:= Result + I;
00523AE4 03D0 add edx,eax
Unit4.pas.34: Inc(I);
00523AE6 40 inc eax
Unit4.pas.35: until I = 50;
00523AE7 83F832 cmp eax,$32
00523AEA 75F8 jnz $00523ae4
Unit4.pas.36: end;
00523AEC 8BC2 mov eax,edx
00523AEE C3 ret

我们发现反汇编代码和For是一样的.
这段代码就和VC反编译出来的差不多了,先执行循环体然后再比较边界.
好,看看while呢?

1
2
3
4
5
6
7
8
9
10
11
12
Function TestWhile(A, B: Integer): Integer;
Var
I: Integer;
Begin
Result:= A+ B;
I:= 0;
While I< 50 Do
Begin
Result:= Result+ I;
Inc(I);
End;
End;

反汇编代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Unit4.pas.38: Result:= A+ B;
00523AE0 03D0 add edx,eax
Unit4.pas.39: I:= 0;
00523AE2 33C0 xor eax,eax
Unit4.pas.42: Result:= Result+ I;
00523AE4 03D0 add edx,eax
Unit4.pas.43: Inc(I);
00523AE6 40 inc eax
Unit4.pas.40: While I< 50 Do
00523AE7 83F832 cmp eax,$32
00523AEA 7CF8 jl $00523ae4
Unit4.pas.45: End;
00523AEC 8BC2 mov eax,edx
00523AEE C3 ret

我晕,居然还是一样的.也就是Delphi里面3种循环执行效率是一样的吧.
而VC同样是先初始化循环变量,然后无条件跳转到边界检测,然后才执行循环体代码.
循环就这么多,以后该是条件判断

-------------本文已结束赏个小钱吧-------------
×

感谢您的支持,我们会一直保持!

扫码支持
请土豪扫码随意打赏

打开微信扫一扫,即可进行扫码打赏哦

分享从这里开始,精彩与您同在

64.7K