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