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


======================================================
注:本文源代码点此下载
======================================================

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的内容:

代码:

004403ec55pushebp

004403ed8becmovebp, esp

004403ef83c4d8addesp, -$28;空出地方放局部变量

004403f253pushebx

004403f356pushesi

004403f457pushedi

004403f533c9xorecx, ecx

004403f7894dd8mov[ebp-$28], ecx

004403fa33c0xoreax, eax

004403fc55pushebp

* possible string reference to: '関-?腽_^[嬪]?

|

004403fd68e9044400push$004404e9

***** try

|

0044040264ff30pushdword ptr fs:[eax];这是delphi的例行公事

00440405648920movfs:[eax], esp;据我观察只要调用vcl库的都要seh

00440408bb01000000movebx, $00000001;a:=1

0044040dbe02000000movesi, $00000002;b:=2

00440412bf03000000movedi, $00000003;c:=3

00440417c745fc04000000movdword ptr [ebp-$04], $00000004;d:=4

0044041ec745f805000000movdword ptr [ebp-$08], $00000005;e:=5

可以看出delphi的确不一样,把ebx,esi,edi能用的寄存器全都用上了,实在不行了才用[ebp-xx],

从下面的分析中也能看出这一点,delphi在能用寄存器时决不用堆栈。

004404258bc3moveax, ebx;这是add1的参数啦,不用push的

* reference to : tform1.proc_00440360()

|

00440427e834ffffffcall00440360;call add1

{

0044036003c0addeax, eax

00440362c3ret;这样的确很快哟

}

0044042c8945f4mov[ebp-$0c], eax;s1:=add1(a)

0044042f8bd6movedx, esi;add2的参数edx=2

004404318bc3moveax, ebx;add2的参数eax=1

* reference to : tform1.proc_00440364()

|

00440433e82cffffffcall00440364;call add2

{

0044036403d0addedx, eax

004403668bc2moveax, edx

00440368c3ret

}

004404388945f0mov[ebp-$10], eax;s2:=add2(a,b)

0044043b8bcfmovecx, edi;add3的参数ecx=3

0044043d8bd6movedx, esi;edx=2

0044043f8bc3moveax, ebx;eax=1

* reference to : tform1.proc_0044036c()

|

00440441e826ffffffcall0044036c;call add3

{

0044036c03d0addedx, eax

0044036e03caaddecx, edx

004403708bc1moveax, ecx

00440372c3ret

}

004404468945ecmov[ebp-$14], eax;s3:=add3(a,b,c)

004404498b45fcmoveax, [ebp-$04];[ebp-4]=4

0044044c50pusheax;终于看见push了噢

0044044d8bcfmovecx, edi;ecx=3

0044044f8bd6movedx, esi;edx=2

004404518bc3moveax, ebx;eax=1

* reference to : tform1.proc_00440374()

|

00440453e81cffffffcall00440374;call add4

{

0044037455pushebp

004403758becmovebp, esp;这是c里面的方式啦

0044037703d0addedx, eax

0044037903caaddecx, edx

0044037b034d08addecx, [ebp+$08];[ebp+8]本来是第一个参数的

0044037e8bc1moveax, ecx;这里[ebp+8]是第四个参数

004403805dpopebp

00440381c20400ret$0004

}

004404588945e8mov[ebp-$18], eax;s4:=add4(a,b,c,d)

0044045b8b45fcmoveax, [ebp-$04];[ebp-4]=4

0044045e50pusheax;注意:先压进去的是第四个参数

0044045f8b45f8moveax, [ebp-$08];[ebp-8]=5

0044046250pusheax;再压进第五个参数,pascal从左至右

004404638bcfmovecx, edi;ecx=3

004404658bd6movedx, esi;edx=2

004404678bc3moveax, ebx;eax=1

* reference to : tform1.proc_00440384()

|

00440469e816ffffffcall00440384;call add5(a,b,c,d,e)

0044046e8945e4mov[ebp-$1c], eax;s5=add5(a,b,c,d,e)

* reference to : tform1.proc_00440398()

|

00440471e822ffffffcall00440398;add6 看看dlephi怎么处理局部变量

{

0044039853pushebx

0044039956pushesi

0044039ab801000000moveax, $00000001

0044039fba02000000movedx, $00000002

004403a4b903000000movecx, $00000003

004403a9bb04000000movebx, $00000004

004403aebe05000000movesi, $00000005;哈哈,果然不出所料

004403b303d0addedx, eax;它用上了一切能用的寄存器

004403b503caaddecx, edx;各位可以试试加上十来个局部变量

004403b703d9addebx, ecx;看它能坚持到几时

004403b903f3addesi, ebx

004403bb8bc6moveax, esi

004403bd5epopesi

004403be5bpopebx

004403bfc3ret

}

004404768945e0mov[ebp-$20], eax

004404798b45fcmoveax, [ebp-$04]

0044047c50pusheax

0044047d8b45f8moveax, [ebp-$08]

0044048050pusheax

004404818bcfmovecx, edi

004404838bd6movedx, esi

004404858bc3moveax, ebx

* reference to : tform1.proc_004403c0();我想看看用result是不是有不同

|

00440487e834ffffffcall004403c0;其实和add5一样的,不写了

0044048c8945dcmov[ebp-$24], eax

0044048f8b45f8moveax, [ebp-$08]

0044049250pusheax;push 5

004404938b45fcmoveax, [ebp-$04]

0044049650pusheax;push 4

0044049757pushedi;push 3

0044049856pushesi;push 2

0044049953pushebx;push 1

* reference to : tform1.proc_004403d4()

|

0044049ae835ffffffcall004403d4;这个眼熟的吧,从右至左的stdcall方式

{

004403d455pushebp

004403d58becmovebp, esp

004403d78b4508moveax, [ebp+$08]

004403da03450caddeax, [ebp+$0c]

004403dd034510addeax, [ebp+$10]

004403e0034514addeax, [ebp+$14]

004403e3034518addeax, [ebp+$18]

004403e65dpopebp

004403e7c21400ret$0014;我还是觉得这样好看一些

}

* reference to form1

|

0044049f8b5df4movebx, [ebp-$0c]

004404a2035df0addebx, [ebp-$10]

004404a5035decaddebx, [ebp-$14]

004404a8035de8addebx, [ebp-$18]

004404ab035de4addebx, [ebp-$1c]

004404ae035de0addebx, [ebp-$20]

004404b1035ddcaddebx, [ebp-$24]

004404b403d8addebx, eax;加起来

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

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

建一个form,放一个button,一个edit,代码如下:

代码:

procedure tform1.button1click(sender: tobject);

begin

messagedlg(edit1.text,mtconfirmation,[mbok],0);

end;

呵呵太简单了是不是,用dede反下:(只写了关键部分)

代码:

004417be6a00push$00;这是下面messagedlg的第四个参数,找到没

004417c08d55fcleaedx, [ebp-$04];??这是什么??

* reference to control tform1.edit1 : tedit

|

004417c38b83c8020000moveax, [ebx+$02c8];这是下面gettext的参数tcontrol吧

;看上面的reference

* reference to: controls.tcontrol.gettext(tcontrol):tcaption;

|

004417c9e8d619feffcall004231a4;得到edit的文本

004417ce8b45fcmoveax, [ebp-$04];这是参数一要显示的字串放入eax

004417d1668b0d00184400movcx, word ptr [$00441800];这应该是参数二mtconfirmation

004417d8b203movdl, $03;这是参数三[mbok]

* reference to: dialogs.proc_00441380

|

004417dae8a1fbffffcall00441380;这个是messagedlg

004417df33c0xoreax, 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中返回,而是在保存一个隐藏的参数中,等需要时再复制过来。(这一点是猜想而已,如果哪位高人知道的话还请指点。反正我以前都是糊里糊涂地跟,结果出来就算了。其实仔细一分析还有点意思。)

绿色通道:好文要顶关注我收藏该文与我联系


======================================================
在最后,我邀请大家参加新浪APP,就是新浪免费送大家的一个空间,支持PHP+MySql,免费二级域名,免费域名绑定 这个是我邀请的地址,您通过这个链接注册即为我的好友,并获赠云豆500个,价值5元哦!短网址是http://t.cn/SXOiLh我创建的小站每天访客已经达到2000+了,每天挂广告赚50+元哦,呵呵,饭钱不愁了,\(^o^)/
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值