delphi if...else...语句和函数参数传递

来源:互联网 发布:windows10网络受限 编辑:程序博客网 时间:2024/05/29 19:18

1if语句

if-then型语句,仅当条件满足时,语句才执行;对if-then-else型,if语句在两条语句中选择一条执行。条件用布尔表达式建立,句子中的条件部分可以是一系列条件(用and、 or 、 not等布尔操作符联接起来),if语句又可以嵌套另一个if语句,要注意的是,不能在第一句之后、else 关键词之前加分号,否则编译器将告知语法错误。

 

if ....then
     begin
      .......

      with ..... do
            begin
              .......           

            end;

      if .... then
            begin
             ....            

             end
             else
                begin
                 .....            

                end ;//endIf

      end//endBegin
 else
      begin
       .......         

       end;

上例中绿色end可以加分号,而红色end不能加分号,即为“不能在第一句之后、else 关键词之前加分号,否则编译器将告知语法错误。

2参数传递

这个帖子写得比较详细:http://www.pediy.com/bbshtml/BBS6/pediy6572.htm

关于Delphi中参数的传递和函数值的返回

前言:

高手们应该早知道了,不屑于写出来而已。真正的高手一个比一个潜的深,只剩下偶这样的小菜写些菜文给更小的菜。高手看时还请捂好大牙,多多指点。

不知各位小菜同胞对破解DELPHI程序有什么看法,反正我的感觉就一个字:怪。各位最先遇到的问题恐怕都是:我下了GetDlgItemInt、GetDlgItemText、GetWindowText....怎么什么也断不下来,甚至连Hmemcpy都不起作用?呵呵,从这里就能看出宝蓝的那批人成心想跟M$对着干,非搞出些新鲜的东东不可。

这回我们就来看看DLEPHI中对函数(过程)参数的传递是如何进行的。

我们知道WinAPI采用的调用约定是StdCall,也就是调用一个函数Func(arg1,agr2,agr3,arg4),你需要push arg4,push arg3,push arg2,push arg1,call Func 。在VC++里也是这种形式,所以一个函数有几个参数,可以非常直观地看出来。可是在DELPHI中就很奇怪了,在一个CALL前面你可能一个PUSH也看不到,怎么回事呢?听我慢慢道来。

DELPHI中的调用约定有StdCall,Cdecl,Safecall,Pascal和Register等几种方式,而DELPHI的默认方式是Register(为什么不是Pascal?)Register方式就是尽可能地使用寄存器来传递参数,减少堆栈的操作来提高速度。具体情况是怎样呢,看个例子先:

在FORM上放一个BUTTON,双击写代码如下:

代码:
function add1(a:Integer):Integer;    //一个参数begin     add1:=a+a;end;function add2(a,b:Integer):Integer;    //两个参数begin     add2:=a+b;end;function add3(a,b,c:Integer):Integer;    //三个参数begin     add3:=a+b+c;end;function add4(a,b,c,d:Integer):Integer;    //四个参数begin     add4:=a+b+c+d;end;function add5(a,b,c,d,e:Integer):Integer;  //五个参数begin     add5:=a+b+c+d+e;end;function add6:Integer;        //加入一些局部变量var local1,local2,local3,local4,local5:Integer;begin     local1:=1;     local2:=2;     local3:=3;     local4:=4;     local5:=5;     add6:=local1+local2+local3+local4+local5;end;function add7(a,b,c,d,e:Integer):Integer;  //利用result来返回begin     result:=a+b+c+d+e;end;function add8(a,b,c,d,e:Integer):Integer;StdCall;//StdCall调用方式begin     add8:=a+b+c+d+e;end;procedure TForm1.Button1Click(Sender: TObject);var a,b,c,d,e:Integer;    s1,s2,s3,s4,s5,s6,s7,s8,s:Integer;begin     a:=1; b:=2; c:=3; d:=4; e:=5;     s1:=add1(a);     s2:=add2(a,b);     s3:=add3(a,b,c);     s4:=add4(a,b,c,d);     s5:=add5(a,b,c,d,e);     s6:=add6;     s7:=add7(a,b,c,d,e);     s8:=add8(a,b,c,d,e);     s:=s1+s2+s3+s4+s5+s6+s7+s8;      //必须要有这么几句     MessageDlg(IntToStr(s),mtConfirmation,[mbOK],0);  //不然编译器根本不去处理返回值end;

用DEDE反一下看看,这个Button1Click的内容:
代码:
004403EC   55                     push    ebp004403ED   8BEC                   mov     ebp, esp004403EF   83C4D8                 add     esp, -$28    ;空出地方放局部变量004403F2   53                     push    ebx004403F3   56                     push    esi004403F4   57                     push    edi004403F5   33C9                   xor     ecx, ecx004403F7   894DD8                 mov     [ebp-$28], ecx004403FA   33C0                   xor     eax, eax004403FC   55                     push    ebp* Possible String Reference to: '関-?腽_^[嬪]?|004403FD   68E9044400             push    $004404E9***** TRY|00440402   64FF30                 push    dword ptr fs:[eax]  ;这是DELPHI的例行公事00440405   648920                 mov     fs:[eax], esp    ;据我观察只要调用VCL库的都要SEH00440408   BB01000000             mov     ebx, $00000001  ;a:=10044040D   BE02000000             mov     esi, $00000002  ;b:=200440412   BF03000000             mov     edi, $00000003  ;c:=300440417   C745FC04000000         mov     dword ptr [ebp-$04], $00000004  ;d:=40044041E   C745F805000000         mov     dword ptr [ebp-$08], $00000005  ;e:=5可以看出DELPHI的确不一样,把EBX,ESI,EDI能用的寄存器全都用上了,实在不行了才用[ebp-xx],从下面的分析中也能看出这一点,DELPHI在能用寄存器时决不用堆栈。00440425   8BC3                   mov     eax, ebx    ;这是add1的参数啦,不用PUSH的* Reference to : TForm1.Proc_00440360()|00440427   E834FFFFFF             call    00440360    ;CALL add1{  00440360   03C0                   add     eax, eax  00440362   C3                     ret      ;这样的确很快哟}0044042C   8945F4                 mov     [ebp-$0C], eax  ;s1:=add1(a)0044042F   8BD6                   mov     edx, esi    ;add2的参数EDX=200440431   8BC3                   mov     eax, ebx    ;add2的参数EAX=1* Reference to : TForm1.Proc_00440364()|00440433   E82CFFFFFF             call    00440364    ;CALL add2{  00440364   03D0                   add     edx, eax    00440366   8BC2                   mov     eax, edx  00440368   C3                     ret}00440438   8945F0                 mov     [ebp-$10], eax  ;s2:=add2(a,b)0044043B   8BCF                   mov     ecx, edi    ;add3的参数ECX=30044043D   8BD6                   mov     edx, esi    ;EDX=20044043F   8BC3                   mov     eax, ebx    ;EAX=1* Reference to : TForm1.Proc_0044036C()|00440441   E826FFFFFF             call    0044036C    ;CALL add3{  0044036C   03D0                   add     edx, eax  0044036E   03CA                   add     ecx, edx  00440370   8BC1                   mov     eax, ecx  00440372   C3                     ret}00440446   8945EC                 mov     [ebp-$14], eax  ;s3:=add3(a,b,c)00440449   8B45FC                 mov     eax, [ebp-$04]  ;[EBP-4]=40044044C   50                     push    eax      ;终于看见PUSH了噢0044044D   8BCF                   mov     ecx, edi    ;ECX=30044044F   8BD6                   mov     edx, esi    ;EDX=200440451   8BC3                   mov     eax, ebx    ;EAX=1* Reference to : TForm1.Proc_00440374()|00440453   E81CFFFFFF             call    00440374    ;CALL add4{  00440374   55                     push    ebp  00440375   8BEC                   mov     ebp, esp  ;这是C里面的方式啦  00440377   03D0                   add     edx, eax  00440379   03CA                   add     ecx, edx  0044037B   034D08                 add     ecx, [ebp+$08];[EBP+8]本来是第一个参数的  0044037E   8BC1                   mov     eax, ecx  ;这里[EBP+8]是第四个参数  00440380   5D                     pop     ebp  00440381   C20400                 ret     $0004}00440458   8945E8                 mov     [ebp-$18], eax  ;s4:=add4(a,b,c,d)0044045B   8B45FC                 mov     eax, [ebp-$04]  ;[EBP-4]=40044045E   50                     push    eax      ;注意:先压进去的是第四个参数0044045F   8B45F8                 mov     eax, [ebp-$08]  ;[EBP-8]=500440462   50                     push    eax      ;再压进第五个参数,Pascal从左至右00440463   8BCF                   mov     ecx, edi    ;ECX=300440465   8BD6                   mov     edx, esi    ;EDX=200440467   8BC3                   mov     eax, ebx    ;EAX=1* Reference to : TForm1.Proc_00440384()|00440469   E816FFFFFF             call    00440384    ;CALL add5(a,b,c,d,e)0044046E   8945E4                 mov     [ebp-$1C], eax  ;s5=add5(a,b,c,d,e)* Reference to : TForm1.Proc_00440398()|00440471   E822FFFFFF             call    00440398    ;add6 看看DLEPHI怎么处理局部变量{  00440398   53                     push    ebx  00440399   56                     push    esi  0044039A   B801000000             mov     eax, $00000001  0044039F   BA02000000             mov     edx, $00000002  004403A4   B903000000             mov     ecx, $00000003  004403A9   BB04000000             mov     ebx, $00000004  004403AE   BE05000000             mov     esi, $00000005;哈哈,果然不出所料  004403B3   03D0                   add     edx, eax  ;它用上了一切能用的寄存器  004403B5   03CA                   add     ecx, edx  ;各位可以试试加上十来个局部变量  004403B7   03D9                   add     ebx, ecx  ;看它能坚持到几时  004403B9   03F3                   add     esi, ebx  004403BB   8BC6                   mov     eax, esi  004403BD   5E                     pop     esi  004403BE   5B                     pop     ebx  004403BF   C3                     ret}00440476   8945E0                 mov     [ebp-$20], eax00440479   8B45FC                 mov     eax, [ebp-$04]0044047C   50                     push    eax0044047D   8B45F8                 mov     eax, [ebp-$08]00440480   50                     push    eax00440481   8BCF                   mov     ecx, edi00440483   8BD6                   mov     edx, esi00440485   8BC3                   mov     eax, ebx* Reference to : TForm1.Proc_004403C0()        ;我想看看用result是不是有不同|00440487   E834FFFFFF             call    004403C0    ;其实和add5一样的,不写了0044048C   8945DC                 mov     [ebp-$24], eax0044048F   8B45F8                 mov     eax, [ebp-$08]00440492   50                     push    eax      ;PUSH 500440493   8B45FC                 mov     eax, [ebp-$04]00440496   50                     push    eax      ;PUSH 400440497   57                     push    edi      ;PUSH 300440498   56                     push    esi      ;PUSH 200440499   53                     push    ebx      ;PUSH 1* Reference to : TForm1.Proc_004403D4()|0044049A   E835FFFFFF             call    004403D4  ;这个眼熟的吧,从右至左的StdCall方式{  004403D4   55                     push    ebp  004403D5   8BEC                   mov     ebp, esp  004403D7   8B4508                 mov     eax, [ebp+$08]  004403DA   03450C                 add     eax, [ebp+$0C]  004403DD   034510                 add     eax, [ebp+$10]  004403E0   034514                 add     eax, [ebp+$14]  004403E3   034518                 add     eax, [ebp+$18]  004403E6   5D                     pop     ebp  004403E7   C21400                 ret     $0014    ;我还是觉得这样好看一些}* Reference to Form1|0044049F   8B5DF4                 mov     ebx, [ebp-$0C]004404A2   035DF0                 add     ebx, [ebp-$10]004404A5   035DEC                 add     ebx, [ebp-$14]004404A8   035DE8                 add     ebx, [ebp-$18]004404AB   035DE4                 add     ebx, [ebp-$1C]004404AE   035DE0                 add     ebx, [ebp-$20]004404B1   035DDC                 add     ebx, [ebp-$24]004404B4   03D8                   add     ebx, eax    ;加起来

........下面的不写了,还值得一提的是在最后DELPHI总要弄出两个RET来,跳来跳去的,也算是DELPHI的特色吧。

上面讲的是自己定义的函数,要是用VCL库的东东,有时候更加莫名其妙一些。看例子:

建一个FORM,放一个BUTTON,一个EDIT,代码如下:
代码:
procedure TForm1.Button1Click(Sender: TObject);begin     MessageDlg(edit1.text,mtConfirmation,[mbOK],0);end;

呵呵太简单了是不是,用DEDE反下:(只写了关键部分)
代码:
004417BE   6A00                   push    $00    ;这是下面MessageDlg的第四个参数,找到没004417C0   8D55FC                 lea     edx, [ebp-$04];??这是什么??* Reference to control TForm1.Edit1 : TEdit|004417C3   8B83C8020000           mov     eax, [ebx+$02C8]  ;这是下面GetText的参数TControl吧                ;看上面的Reference* Reference to: controls.TControl.GetText(TControl):TCaption;|004417C9   E8D619FEFF             call    004231A4  ;得到EDIT的文本004417CE   8B45FC                 mov     eax, [ebp-$04];这是参数一要显示的字串放入EAX004417D1   668B0D00184400         mov     cx, word ptr [$00441800];这应该是参数二mtConfirmation004417D8   B203                   mov     dl, $03  ;这是参数三[mbOK]* Reference to: Dialogs.Proc_00441380|004417DA   E8A1FBFFFF             call    00441380  ;这个是MessageDlg004417DF   33C0                   xor     eax, eax

如果按照上面的分析,看到GetText这里应该只有一个参数就是放入EAX的那个[ebx+02c8],从参考也可以看到这就是EDIT1,可是函数的返回值呢?刚执行完这个CALL后EAX中是没有的,mov eax,[ebp-04]后才出现了,返回值原来在[ebp-4]中。再向上找有一个莫名其妙的lea edx,[ebp-04],按照我上面的分析这应该表示GetText的第二个参数。可是GetText只有一个参数呀。
这种需要返回一个比较大的结构的函数,在VC中常用的方法是把一个指针当参数传递过去,而DLEPHI中我猜是不是做成一个隐藏的参数,像上面的GetText表面上看是返回一个TCaption,实际这个并不是放在EAX里返回来的。

总结一下:DELPHI对参数的传递是尽可能多地利用寄存器,一般第一个参数用EAX,第二个参数用EDX,第三个参数用ECX,多于三个参数的时候,对多出来的参数按照从左至右的PASCAL方式来压栈。
对于函数的返回值,有时尽管声明中说它的返回值是TCaption之类等,实际上并没有在EAX中返回,而是在保存一个隐藏的参数中,等需要时再复制过来。(这一点是猜想而已,如果哪位高人知道的话还请指点。反正我以前都是糊里糊涂地跟,结果出来就算了。其实仔细一分析还有点意思。)


 

 

原创粉丝点击