主题:调用约定演示例子
主持:A3.武稀松
时间:2005-02-01 15:00

2005-02-01 14:50:02 A3.武稀松(42088303)
本来想找一点时间给大家讲一下组件设计,BASM等.时间不太够.所以今天下午抽出一小段时间说一下调用约定

2005-02-01 14:51:26 A3.武稀松(42088303)
大家都知道Delphi最常用得函数调用约定方式吧

2005-02-01 14:51:27 乾隆(7891551)
谁再安排下讲点最简单的东西吧,比如类好吗

2005-02-01 14:52:07 D8 。飘尘(43745429)
从左还是从右传值对吧

2005-02-01 14:52:23 A3.武稀松(42088303)
很多书上都有,什么从左到右传参数,从右到左传参数得.我就给大家一些形象具体的例子开始讲起

2005-02-01 14:52:55 B4.松鼠(64652023)
A3在会议室开课哦

2005-02-01 14:53:03 A3.武稀松(42088303)
D8你说Delphi最常见的几种调用约定都有什么呢

2005-02-01 14:53:17 乾隆(7891551)
好,什么是从左到右,什么是从右到左?

2005-02-01 14:53:35 D8 。飘尘(43745429)
有4种吧,偶不记得了

2005-02-01 14:53:43 A1.笑熬糨糊(2282902)
我们可以从最简单的方式讲起。

2005-02-01 14:53:50 D8.飘尘(43745429)
STDCALL偶记得了

2005-02-01 14:53:52 A1.笑熬糨糊(2282902)
就是Delphi默认的方式。

2005-02-01 14:54:13 A3.武稀松(42088303)
第一种Delphi默认的调用方是Register寄存器方式

2005-02-01 14:54:26 D8 。飘尘(43745429)
Register对对

2005-02-01 14:54:42 A3.武稀松(42088303)
procedure A(Param1,Param2:String);register;
begin
  ShowMessage(Param1+Param2);
end;

2005-02-01 14:55:32 A3.武稀松(42088303)
register关键字就是表示寄存器传参数方式,如果没有说明的话,编译器默认就编译成这种形式

2005-02-01 14:56:04 A1.笑熬糨糊(2282902)
Right,正解!

2005-02-01 14:56:07 A3.武稀松(42088303)
这种调用传递参数的方式是这样:
从左到右,优先使用寄存器(EAX,EDX,ECX),然后使用栈(也就是剩下的参数采用Pascal方式调用)
Delphi默认调用方式,是运行效率最高的调用方式.

2005-02-01 14:57:02 A3.武稀松(42088303)
形象一点给大家用汇编写一下调用的例子就明白了

2005-02-01 14:57:18 A1.笑熬糨糊(2282902)
就上午的例子也可以了。

2005-02-01 14:57:29 A3.武稀松(42088303)
procedure TForm1.Button1Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  A('A','B');
end;


2005-02-01 14:58:04 A3.武稀松(42088303)
调用我上面说的函数,实际上和这样的调用等价 

2005-02-01 14:58:11 A3.武稀松(42088303)
procedure TForm1.Button1Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  //A('A','B');
  asm
    push EAX    //把EAX压入栈中,就是保存起来
    mov EAX, lA //把lA付给第一个参数
    mov EDX, lB //把lB付给第二个参数
    call A      //调用A
    pop EAX     //把EAX从栈中弹出,回复EAX
  end;
end;


2005-02-01 14:59:38 A3.武稀松(42088303)
    mov EAX, lA //把lA付给第一个参数
    mov EDX, lB //把lB付给第二个参数
这两行就是把参数放进寄存器中

2005-02-01 14:59:50 A1.笑熬糨糊(2282902)
Right,正解!

2005-02-01 15:00:12 A3.武稀松(42088303)
这个可能是比较常用的调用方式中效率最高的了

2005-02-01 15:00:33 A3.武稀松(42088303)
//有人谁说VC的__fastcall方式效率也差不多
__fastcall从右到左,优先使用寄存器(ECX,EDX),然后使用栈.关键是EAX寄存器的速度最快
所以还是Delphi的Regiser方式效率要搞一点,而且多了一个用寄存器传递的参数在参数大于
2个的时候效率更加明显,因为栈比寄存器要慢

2005-02-01 15:00:46 乾隆(7891551)
//A('A','B');这句啥意思

2005-02-01 15:01:13 A3.武稀松(42088303)
我注释掉的.和我下面的汇编代码等价

2005-02-01 15:01:14 兰铃子(105351942)
A,B连接

2005-02-01 15:01:27 A3.武稀松(42088303)
procedure A(Param1,Param2:String);register;
begin
  ShowMessage(Param1+Param2);
end; 

2005-02-01 15:01:34 A3.武稀松(42088303)
调用函数A

2005-02-01 15:01:43 乾隆(7891551)
连成个新的字符'AB'给变量A吗

2005-02-01 15:01:49 D10.天地弦(185511468)
所以参数2个最适合?

2005-02-01 15:02:06 B6.银狼(43225570)
武大写的例子么?给我一个被

2005-02-01 15:02:08 A3.武稀松(42088303)
不一定两个最合适

2005-02-01 15:02:22 D8 。飘尘(43745429)
什么事呀

2005-02-01 15:02:25 A3.武稀松(42088303)
我的例子是一边说一边写的

2005-02-01 15:02:37 B6.银狼(43225570)

2005-02-01 15:02:35 太/rose阳(5704127)
3哥,真棒!

2005-02-01 15:02:52 D3.天之痕若虹(86278566)
晕,睡过头了

2005-02-01 15:02:59 A3.武稀松(42088303)
我们在来说一下第二种调用方式  Pascal方式

2005-02-01 15:03:21 A1.笑熬糨糊(2282902)
参数三个之内比较适合。

2005-02-01 15:04:03 D10.天地弦(185511468)
也就是这个原因?

2005-02-01 15:04:04 A3.武稀松(42088303)
A1说得对,三个以内效率最高.大于三个,后面的参数效率和Pascal方式相同

2005-02-01 15:04:51 A3.武稀松(42088303)
Pascal方式参数传递从左到右,通过栈传递
这个是Win31时代API的标准调用方式,讽刺意味的是当时看不起Pascal的C程序员也不得不这样调用

2005-02-01 15:04:59 A3.武稀松(42088303)
我们把刚才的函数修改一下

2005-02-01 15:05:07 A3.武稀松(42088303)
procedure B(Param1,Param2:String);Pascal;
begin
  ShowMessage(Param1+Param2);
end;

2005-02-01 15:05:19 A3.武稀松(42088303)
这样的形式就是Pascal方式调用

2005-02-01 15:05:31 乾隆(7891551)
哦,长知识了,呵呵

2005-02-01 15:06:19 D10.天地弦(185511468)
pascal是从左到右?

2005-02-01 15:06:29 D10.天地弦(185511468)
stdcall, safecall是从右到左


2005-02-01 15:06:42 D10.天地弦(185511468)
register是从左到右


2005-02-01 15:07:04 A3.武稀松(42088303)
D10我说的Pascal方式还没说道那两种方式呢

2005-02-01 15:07:05 A3.武稀松(42088303)
procedure TForm1.Button2Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  //B('A','B');
  asm
    push la  //把la压入栈
    push lb  //把lb压入栈
    call B
  end;
end;

2005-02-01 15:07:54 A3.武稀松(42088303)
D10看我把la和lb压入栈得顺序,你说参数的顺序是先左还是还是先右呢

2005-02-01 15:08:03 D10.天地弦(185511468)
==

2005-02-01 15:08:09 D10.天地弦(185511468)
lb,la

2005-02-01 15:08:15 A3.武稀松(42088303)
好,大家可以执行一下我上面的代码

2005-02-01 15:08:34 D10.天地弦(185511468)
pop时先出来lb,再la

2005-02-01 15:08:39 A3.武稀松(42088303)
我也趁机写下两种调用方式的例子

2005-02-01 15:08:46 乾隆(7891551)
LA,LB是什么,我只听过AX,BX,CX,DX,什么时候来了个LA,LB啊

2005-02-01 15:09:06 A1.笑熬糨糊(2282902)
变量。

2005-02-01 15:09:06 D10.天地弦(185511468)
变量

2005-02-01 15:09:09 A3.武稀松(42088303)
乾隆,那两个是普通变量!!!

2005-02-01 15:09:22 D10.天地弦(185511468)
不看申明

2005-02-01 15:09:26 乾隆(7891551)
啊[:L]我以为是很 高深的东西呢

2005-02-01 15:09:27 A3.武稀松(42088303)
可能是我的名字起的不好

2005-02-01 15:09:44 A1.笑熬糨糊(2282902)
还好不是起个AX是BX

2005-02-01 15:10:10 A3.武稀松(42088303)
要是AL,BL也不行啊

2005-02-01 15:10:44 D10.天地弦(185511468)
3哥,你这个Demo有没有共享?

2005-02-01 15:10:45 A3.武稀松(42088303)
这个调用方是还有什么疑问么,我要往下说了


2005-02-01 15:11:00 乾隆(7891551)
对,我的表达能力非常好,等我成高手了,讲课没有人听不懂的,我能把猪都教会编程,嘿嘿

2005-02-01 15:11:04 A3.武稀松(42088303)
我一边讲,一边写.现在没有现成的DEMO

2005-02-01 15:11:15 A1.笑熬糨糊(2282902)
[coffee]

2005-02-01 15:11:24 D10.天地弦(185511468)
[;P]

2005-02-01 15:11:50 D8 。飘尘(43745429)
pop时先出来lb,再la 错了吧

2005-02-01 15:11:57 D8 。飘尘(43745429)
是先LA 再LB吧

2005-02-01 15:12:16 D10.天地弦(185511468)
谁说

2005-02-01 15:12:22 乾隆(7891551)
后压的先出来

2005-02-01 15:12:28 D10.天地弦(185511468)

2005-02-01 15:12:29 A3.武稀松(42088303)
不用Pop

2005-02-01 15:12:33 D8 。飘尘(43745429)
看错了。我以为先进LA了

2005-02-01 15:12:57 A3.武稀松(42088303)
因为参数的恢复是被调用方负责的

----------------------运行没反应的原因
2005-02-01 15:23:24 A1.笑熬糨糊(2282902)
是QQ的原因,因为,QQ复制是,只COPY了#13,没有COPY#10,所以Delphi编译出错
----------------------

2005-02-01 15:25:33 A3.武稀松(42088303)
既然解决了,我们就接着说下一个stdcall方式调用

2005-02-01 15:26:03 A3.武稀松(42088303)
从右到左,通过堆栈传递
VB默认就是这个调用方式,Win32的API也是采用这种声明方式

2005-02-01 15:26:23 D10.天地弦(185511468)
从右到左

2005-02-01 15:26:25 D10.天地弦(185511468)

2005-02-01 15:26:36 D10.天地弦(185511468)
是说stdcall,safecall?

2005-02-01 15:26:42 A3.武稀松(42088303)

procedure C(Param1,Param2:String);stdcall; //SafeCall编译器特殊处理等同Stdcall
begin
  ShowMessage(Param1+Param2);
end;

2005-02-01 15:26:50 兰铃子(105351942)
我也OK了。

2005-02-01 15:27:59 A3.武稀松(42088303)
procedure TForm1.Button3Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  //B('A','B');
  asm
    push lb
    push la
    call C
  end;
end;
D10看看参数的传递次序

2005-02-01 15:28:24 A3.武稀松(42088303)
你看先把哪个一个参数压入栈里面的

2005-02-01 15:28:25 兰铃子(105351942)
BA

2005-02-01 15:28:34 D10.天地弦(185511468)
是从右到左

2005-02-01 15:28:55 A3.武稀松(42088303)
兰铃子的反了

2005-02-01 15:28:58 A3.武稀松(42088303)
是AB

2005-02-01 15:29:02 兰铃子(105351942)

2005-02-01 15:29:11 兰铃子(105351942)
我没把LB,LA,换了

2005-02-01 15:29:19 兰铃子(105351942)
道理一样啦。呵呵

2005-02-01 15:29:36 A3.武稀松(42088303)
现在的API的调用约定都是这样的

2005-02-01 15:29:36 D10.天地弦(185511468)
[:L]

2005-02-01 15:30:28 D10.天地弦(185511468)
==

2005-02-01 15:30:31 D10.天地弦(185511468)
3哥

2005-02-01 15:30:34 A3.武稀松(42088303)
我们写DLL的时候通常也采用这样的调用方式,主要是为了和其他的语言兼容.如果紧紧在Delphi中使用我建议使用寄存器方式调用

2005-02-01 15:30:36 兰铃子(105351942)
长知识了。

2005-02-01 15:30:47 A3.武稀松(42088303)
D10要说什么

2005-02-01 15:31:02 D10.天地弦(185511468)
  asm
    push la;  //把la压入栈
    push lb;  //把lb压入栈
    call b;
  end;
一样的
b(la,lb)

2005-02-01 15:31:06 D10.天地弦(185511468)
是吧

2005-02-01 15:31:15 A3.武稀松(42088303)
什么意思

2005-02-01 15:31:26 A3.武稀松(42088303)
对呀,就是次序不对而已

2005-02-01 15:32:01 兰铃子(105351942)
B是什么方式的啊 ?

2005-02-01 15:32:10 A3.武稀松(42088303)
B是Pascal方式的

2005-02-01 15:32:18 兰铃子(105351942)

2005-02-01 15:32:40 A3.武稀松(42088303)
我们代码写的简单,编译器好辛苦啊.他要按照函数的声明不同,编译出不一样的代码

2005-02-01 15:33:07 A3.武稀松(42088303)
这个调用约定没问题了吧

2005-02-01 15:33:16 兰铃子(105351942)
如果B是stdcall方式的呢?

2005-02-01 15:33:27 A3.武稀松(42088303)
C不就是么

2005-02-01 15:33:46 A3.武稀松(42088303)
我要继续讲下一个调用约定了

2005-02-01 15:34:00 兰铃子(105351942)
procedure TForm1.Button2Click(Sender: TObject);
var
la,lb:string;
begin
la:='a';
lb:='b';
c(la,lb);

2005-02-01 15:34:08 A3.武稀松(42088303)
cdecl方式的调用

2005-02-01 15:34:17 兰铃子(105351942)
运行结果是什么啊?

2005-02-01 15:34:49 A3.武稀松(42088303)
等下再说.我先继续

2005-02-01 15:35:09 A3.武稀松(42088303)
cdecl参数是从右到左,通过堆栈传递(与C\C++默认调用约定兼容)比较原始,需要约定需要调用者来清除堆栈

2005-02-01 15:35:49 A3.武稀松(42088303)
大家看cdecl和stdcall的约定有什么区别?

2005-02-01 15:35:58 A3.武稀松(42088303)
D10你来说说

2005-02-01 15:37:02 A3.武稀松(42088303)
D10是不是溜了

2005-02-01 15:38:28 A1.笑熬糨糊(2282902)
我在试中。。。

2005-02-01 15:38:35 D10.天地弦(185511468)
晕啊

2005-02-01 15:38:42 D10.天地弦(185511468)
我的机又死了一次

2005-02-01 15:39:33 A3.武稀松(42088303)
cdecl和stdcall的区别就在于要调用者手工恢复参数栈,所以说是比较原始的一种方式

2005-02-01 15:39:53 D10.天地弦(185511468)
现在是不是不用了

2005-02-01 15:39:58 D10.天地弦(185511468)
cdecl

2005-02-01 15:40:06 A3.武稀松(42088303)
procedure D(Param1,Param2:String);cdecl ;
begin
  ShowMessage(Param1+Param2);
end;

2005-02-01 15:40:43

D6.岚(151951212)
cdecl这种方式现在已经很少使用了,一般都是用stdcall了

2005-02-01 15:40:56 A3.武稀松(42088303)
调用方式和stdcall很类似,不过要手工恢复栈才行

2005-02-01 15:41:05 D10.天地弦(185511468)

2005-02-01 15:41:19 D10.天地弦(185511468)
我在InsideVCL上都没有介绍这种方式了

2005-02-01 15:41:17 A3.武稀松(42088303)
procedure D(Param1,Param2:String);cdecl ;
begin
  ShowMessage(Param1+Param2);
end;

2005-02-01 15:41:29 A3.武稀松(42088303)
procedure TForm1.Button4Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  asm
    push lb
    push la
    call D
    pop la     //调用方要自己恢复栈
    pop lb     //调用方要自己恢复栈
  end;
end;

2005-02-01 15:41:43 A3.武稀松(42088303)
依然还是可以调用的

2005-02-01 15:42:26 兰铃子(105351942)
怪不得刚才出那样的错了。

2005-02-01 15:42:33 A3.武稀松(42088303)
这种调用方式还是有用的

2005-02-01 15:42:54

D6.岚(151951212)
有什么用?相对而言,不是stdcall会方便一些吗?

2005-02-01 15:42:59 B2.TCP INFO(31329846)
cdecl

2005-02-01 15:43:08

D6.岚(151951212)
cdecl不是早期的东西了吗?

2005-02-01 15:43:14 A3.武稀松(42088303)
C/C++里面依然还在广泛使用.特别是C/C++的主函数必须是cdecl方式的,不能改的

2005-02-01 15:43:28 A3.武稀松(42088303)
C/C++里面依然还在广泛使用.特别是C/C++的主函数必须是cdecl方式的,不能改的 

2005-02-01 15:43:33 B2.TCP INFO(31329846)
由右至左

2005-02-01 15:43:56 D8 。飘尘(43745429)
哈哈以前看过差不多忘记了,还在学校读书时

2005-02-01 15:44:03 A3.武稀松(42088303)
有一些时候例如C里面的Printf函数谁用过?

2005-02-01 15:44:16 兰铃子(105351942)
我用过

2005-02-01 15:44:17 D10.天地弦(185511468)
3哥,如果cdecl不用汇编怎么pop出来

2005-02-01 15:44:18 B2.TCP INFO(31329846)
我这有书,哪里不明,我可以打上来

2005-02-01 15:44:25 D8 。飘尘(43745429)
PRINTF偶当然用过了

2005-02-01 15:44:36 A3.武稀松(42088303)
他的参数数目是不固定的,所以由调用者一方回复会比较方便实现

2005-02-01 15:44:41 D3.天之痕若虹(86278566)
现在可以调用那函数吗?

asm里的

2005-02-01 15:45:12 A3.武稀松(42088303)
D10.天地弦(185511468) 15:44:17
3哥,如果cdecl不用汇编怎么pop出来
----------------------
编译器在编译的时候会处理的,调用完会自动回复参数的

2005-02-01 15:45:25 乾隆(7891551)
 asm
    push lb
    push la
    call D //为什么调用前汇编语言一定呀压入呢,汇编怎么知道要这么做,还知道起调用DELPHI定义的函数,不理解啊

2005-02-01 15:46:05 A3.武稀松(42088303)
乾隆,这是编译器为你做好的.我用汇编写只是让你更清楚编译器都为我们做了什么

2005-02-01 15:46:11 D10.天地弦(185511468)
call 就是调用过程了

2005-02-01 15:46:34 A3.武稀松(42088303)
这四大类我都讲完了.还有一个要提一下

2005-02-01 15:46:56 A1.笑熬糨糊(2282902)
什么东西要提?

2005-02-01 15:46:59 A3.武稀松(42088303)
就是A1上午说的成员函数的问题

2005-02-01 15:47:30 A1.笑熬糨糊(2282902)
就是Self的问题?

2005-02-01 15:47:35 乾隆(7891551)
我在想CALL D  若这个D过程也是在ASM 里用汇编语言写的就可以理解了,用DELPHI前面定义的,汇编竟然也知道怎么调用,奇怪

2005-02-01 15:47:42 兰铃子(105351942)
我要听SELF。

2005-02-01 15:47:46 A3.武稀松(42088303)
成员函数其实也是可以加上这些调用约定的.不加的话默认是寄存器传递参数的方式

2005-02-01 15:48:10 D10.天地弦(185511468)
[v]

2005-02-01 15:48:10

D6.岚(151951212)
在Delphi中,寄存器方式是最快的

2005-02-01 15:48:19 A1.笑熬糨糊(2282902)
如果是调用普通函通,EAX是第一个参数,如果是调用成员函数,EAX是Self.

2005-02-01 15:48:21 D10.天地弦(185511468)
[图片]

2005-02-01 15:48:23 D10.天地弦(185511468)
下面是谁

2005-02-01 15:48:28 D10.天地弦(185511468)
咱没有名

2005-02-01 15:48:27 大羽(393921295)
寄存器有限

2005-02-01 15:48:44 乾隆(7891551)
你讲这几种调用方式结论是想告诉什么,是D10总结的这句吗,若是我记住这句话就可以了,呵呵

2005-02-01 15:48:44 大羽(393921295)
有32个?

2005-02-01 15:48:46 D10.天地弦(185511468)
嗯,

2005-02-01 15:48:47 A3.武稀松(42088303)
但是成员函数有一个特殊的地方,编译器会为它加一个参数Self,而且Self永远都是第一个参数

2005-02-01 15:49:00 A3.武稀松(42088303)
所以

2005-02-01 15:49:50 A3.武稀松(42088303)
A1默认状态下成员函数是寄存器方式,而Self又是第一个参数,所以EAX就是那个Self了

2005-02-01 15:50:02 A1.笑熬糨糊(2282902)
Right,正解!

2005-02-01 15:50:03 A3.武稀松(42088303)
默认状态下成员函数是寄存器方式,而Self又是第一个参数,所以EAX就是那个Self了 

2005-02-01 15:50:27 乾隆(7891551)
EAX和以前的AX寄存器有什么区别啊

2005-02-01 15:50:30 A3.武稀松(42088303)
procedure E(Param1,Param2:String);
.....
procedure TForm1.E(Param1,Param2:String);
begin
  ShowMessage(Param1+Param2 + Self.Caption); 
end;

2005-02-01 15:50:39 D10.天地弦(185511468)
A1.笑熬糨糊(2282902) 15:48:19
如果是调用普通函通,EAX是第一个参数,如果是调用成员函数,EAX是Self.
---------
普能函数EAX也是第一个参数,只是第一个参数为Self

2005-02-01 15:51:06 A3.武稀松(42088303)
EAX是32位寄存器,AX是16位的,EAX的低16位就是旧的AX

2005-02-01 15:51:22 乾隆(7891551)
这样的啊

2005-02-01 15:51:28 A3.武稀松(42088303)
procedure TForm1.Button5Click(Sender: TObject);
var
  lA,lB:String;
begin
  lA:='A';
  lB:='B';
  {
  //E(lA,lB);
  asm
    mov EDX,la
    mov ECX,lb
    //实际上因为是在TForm1.Button5Click方法里面执行,所以EAX现在就是Self,可以省略
    call TForm1.E
  end;}
  //Form1.E(lA,lB);
  asm
    mov EDX,la
    mov ECX,lb
    mov EAX,Form1
    call TForm1.E
  end;
end;

2005-02-01 15:51:29 A1.笑熬糨糊(2282902)
普能函数EAX也是第一个参数,只是第一个参数为Self <-?

2005-02-01 15:51:38 B1.斜阳(249208513)
还有一个不太显著的差别,就是Delphi在对类方法的调用和对普通方法的调用不太一样

2005-02-01 15:52:12 A1.笑熬糨糊(2282902)
B1出来踢局了。[:D]

2005-02-01 15:52:22 A3.武稀松(42088303)
上面的汇编代码就是对成员函数的调用

2005-02-01 15:52:40 B1.斜阳(249208513)
[:X]


2005-02-01 15:53:49 D10.天地弦(185511468)
[:L]

2005-02-01 15:53:50 B1.斜阳(249208513)
Delphi在对类方法和对类中普通方法虽然第一个参数都是self,但是,两个self却不一样,这就是区别了

2005-02-01 15:54:16 A1.笑熬糨糊(2282902)
Right,正解!

2005-02-01 15:54:23 乾隆(7891551)
怎么QQ不动了
 

2005-02-01 15:54:43 B1.斜阳(249208513)
对类方法的调用,其中的self是指向类本身的,对类中普通方法的调用,self是指向类的实例的

2005-02-01 15:54:55 A3.武稀松(42088303)
类方法中的Self指类,普通成员函数的Self指当前实例

2005-02-01 15:55:21 D10.天地弦(185511468)
en

2005-02-01 15:55:36 A3.武稀松(42088303)
我说的EAX中的仅仅是Self.当它是类方法的时候就是类,否则是当前实例

2005-02-01 15:56:09 D10.天地弦(185511468)

2005-02-01 15:56:35 A3.武稀松(42088303)
编译器会在方法所有参数前插入self参数.其实还是普通的寄存器调用方是

2005-02-01 15:56:35 乾隆(7891551)
半明半不明

2005-02-01 15:57:02 D10.天地弦(185511468)
编译器会在方法所有参数前插入self参数.其实还是普通的寄存器调用方式

2005-02-01 15:57:14 A3.武稀松(42088303)
我把代码打包一下,传到共享里

2005-02-01 15:57:56 D10.天地弦(185511468)
D10.天地弦(185511468) 15:53:07
A1.笑熬糨糊(2282902) 15:48:19
如果是调用普通函通,EAX是第一个参数,如果是调用成员函数,EAX是Self.
---------
普能函数EAX也是第一个参数,只是成员函数第一个参数为Self--->开始漏了几个字成员函数

2005-02-01 15:58:12 D10.天地弦(185511468)
A3.武稀松(42088303) 15:56:35
编译器会在方法所有参数前插入self参数.其实还是普通的寄存器调用方,是 .....

2005-02-01 15:58:24 D10.天地弦(185511468)
我开始这样读的

2005-02-01 15:58:23 ygm(81379503)
你们讨论好激烈阿

2005-02-01 15:58:33 ygm(81379503)
很好玩啊 

2005-02-01 15:58:47 A1.笑熬糨糊(2282902)
技术讨论需要激烈

2005-02-01 15:58:48 A3.武稀松(42088303)
已经传到群共享里面了

2005-02-01 15:58:55 ygm(81379503)
可惜我正在赶项目


2005-02-01 15:59:27 ygm(81379503)
聊天记录,以后能看到吗?

2005-02-01 15:59:52 A3.武稀松(42088303)
有一个有趣的现象D10想想为什么会这样

2005-02-01 15:59:59 布袋猫(6148012)
[:D]真的是字符在作怪呢,俺成功了

2005-02-01 16:00:06 A3.武稀松(42088303)
procedure TForm1.Button1Click(Sender: TObject);
var
  B:TButton;
begin
  ShowMessage(B.Caption);
end;

2005-02-01 16:00:06 D10.天地弦(185511468)
我看看

2005-02-01 16:00:25 A3.武稀松(42088303)
和今天说的有一点关系

2005-02-01 16:00:24 D10.天地弦(185511468)
这个?

2005-02-01 16:00:52 A3.武稀松(42088303)
你看看运行结果是什么

2005-02-01 16:00:57 B6.银狼(43225570)
不会错误的?

2005-02-01 16:01:11 B6.银狼(43225570)
是  button1么

2005-02-01 16:01:11 D10.天地弦(185511468)
是Button1

2005-02-01 16:01:20 D10.天地弦(185511468)
奇怪

2005-02-01 16:02:07 B6.银狼(43225570)
奇怪什么?


2005-02-01 16:02:38 D10.天地弦(185511468)
为什么是"Button1"

2005-02-01 16:03:19 B6.银狼(43225570)
上午不是说了

2005-02-01 16:03:51 D10.天地弦(185511468)
老大那个例子

2005-02-01 16:04:02 B6.银狼(43225570)

2005-02-01 16:04:41 D10.天地弦(185511468)
procedure TForm1.Button6Click(Sender: TObject);
var
  B: TButton;
begin
  showmessage(B.Caption);
end;

2005-02-01 16:04:51 D10.天地弦(185511468)
我这里显示是Button6

2005-02-01 16:05:34 D10.天地弦(185511468)
procedure TForm1.FormClick(Sender: TObject);
var
  B: TButton;
begin
  showmessage(B.Caption);
end;

2005-02-01 16:05:38 D10.天地弦(185511468)
是显示Form1

2005-02-01 16:06:05 A3.武稀松(42088303)
呵呵

2005-02-01 16:06:11 A3.武稀松(42088303)
嘿嘿嘿

2005-02-01 16:06:33 B6.银狼(43225570)
[图片]

2005-02-01 16:06:37 B6.银狼(43225570)
我的是这样的

2005-02-01 16:06:41 D10.天地弦(185511468)
3哥,你说说

2005-02-01 16:07:00 D10.天地弦(185511468)
[图片]

2005-02-01 16:07:08 A3.武稀松(42088303)
写在谁的事件里显示的就是谁的Caption

2005-02-01 16:07:17 D10.天地弦(185511468)
B6你换个试试

2005-02-01 16:07:22 D10.天地弦(185511468)
嗯,

2005-02-01 16:07:24 布袋猫(6148012)
有意思,呵呵

2005-02-01 16:07:24 D10.天地弦(185511468)
咱了

2005-02-01 16:07:24 B6.银狼(43225570)

2005-02-01 16:07:41 D10.天地弦(185511468)
是不是这样

2005-02-01 16:07:58 B6.银狼(43225570)
有意思,是的

2005-02-01 16:08:12 D10.天地弦(185511468)
点击的时候有Push一个实例进去

2005-02-01 16:08:17 B6.银狼(43225570)
而且没有该有的退出时的错误

2005-02-01 16:08:27 B6.银狼(43225570)
哦,对,不该有错误

2005-02-01 16:08:33 D10.天地弦(185511468)
B刚好和这个实例都有Caption属性

2005-02-01 16:08:48 D10.天地弦(185511468)
是不是

2005-02-01 16:08:51 B6.银狼(43225570)
要是没有呢

2005-02-01 16:09:06 D10.天地弦(185511468)
error

2005-02-01 16:09:22 A3.武稀松(42088303)
但是你把编译选项的优化选项去掉,重新Build以后在看看执行什么结果

2005-02-01 16:10:05 D10.天地弦(185511468)
出错

2005-02-01 16:10:06 B6.银狼(43225570)
哪个是优化啊,不认识

2005-02-01 16:10:10 布袋猫(6148012)
Tedit没有CAPTION属性

2005-02-01 16:10:23 布袋猫(6148012)
显示的是TEXT内容

2005-02-01 16:10:27 D8 。飘尘(43745429)
武松做一下总结了

2005-02-01 16:10:38 兰铃子(105351942)
/

2005-02-01 16:10:43 兰铃子(105351942)

2005-02-01 16:10:47 A3.武稀松(42088303)
没啥总结的.都讲完了

2005-02-01 16:10:59 D10.天地弦(185511468)
[图片]

2005-02-01 16:11:17 乾隆(7891551)
天讲了些太高深的东西,对我来说现在都用不到,55555555555

2005-02-01 16:11:39 乾隆(7891551)
给我们讲讲基础的东西好吗

2005-02-01 16:11:47 A3.武稀松(42088303)
今天主要是用汇编把各个调用方式写一遍,给大家一个更具体的认识而已

2005-02-01 16:12:09 D8 。飘尘(43745429)
记录太多了。偶看不过来了

2005-02-01 16:12:25 D10.天地弦(185511468)
3哥,是不是那个Integrate debugging编译优化?

2005-02-01 16:12:25 兰铃子(105351942)
?

2005-02-01 16:12:39 A3.武稀松(42088303)
[图片]

2005-02-01 16:12:41 D10.天地弦(185511468)
不是

2005-02-01 16:12:43 D10.天地弦(185511468)
搞错了

2005-02-01 16:12:47 乾隆(7891551)
D10出来,给我把类讲下吧,让群里的菜鸟也能消化点食

2005-02-01 16:12:53 A3.武稀松(42088303)
把这个选项去掉.大家重新Build再看看刚才的代码

2005-02-01 16:13:26 D10.天地弦(185511468)

2005-02-01 16:13:27 B6.银狼(43225570)
可以编译,运行时错误

2005-02-01 16:13:29 D10.天地弦(185511468)
出错

2005-02-01 16:13:46 B6.银狼(43225570)
是个地址错误

2005-02-01 16:13:49 D10.天地弦(185511468)
乾隆(7891551) 16:12:47
D10出来,给我把类讲下吧,让群里的菜鸟也能消化点食 ==>有讲过

2005-02-01 16:14:10 D8 。飘尘(43745429)
D10氢DEMO发一个过来了

2005-02-01 16:14:17 D10.天地弦(185511468)
[:L]

2005-02-01 16:14:21 乾隆(7891551)
可我没听到过啊,照顾下新来的偶啊

2005-02-01 16:14:22 D10.天地弦(185511468)
群的共享里有

2005-02-01 16:14:30 A3.武稀松(42088303)
飘尘,群共享里面有的

2005-02-01 16:14:30 D10.天地弦(185511468)
D8

2005-02-01 16:14:31 B6.银狼(43225570)
这个是什么东西

2005-02-01 16:14:28 B6.银狼(43225570)
[图片]

2005-02-01 16:14:39 B6.银狼(43225570)
帮我看看以前没有的

2005-02-01 16:14:39 D8 。飘尘(43745429)
我上不了了

2005-02-01 16:14:41 乾隆(7891551)
D10再给大家讲次吧,

2005-02-01 16:14:43 D10.天地弦(185511468)
咱这么大

2005-02-01 16:14:50 D10.天地弦(185511468)
[:L]

2005-02-01 16:14:52 B6.银狼(43225570)
delphi 里的

2005-02-01 16:15:01 D8 。飘尘(43745429)
传给了。我是繁休下面的

2005-02-01 16:15:05 B6.银狼(43225570)
就是今天你给我弄来弄去就出来了

2005-02-01 16:15:06 乾隆(7891551)
有没有这么同意我的的意见啊,同意的别说话

2005-02-01 16:15:13 D10.天地弦(185511468)
乾隆我传记录给你

2005-02-01 16:15:15 D8 。飘尘(43745429)
QQ不能用群共享了

2005-02-01 16:15:19 D10.天地弦(185511468)
OK

2005-02-01 16:15:23 乾隆(7891551)
好吧

2005-02-01 16:15:45 B6.银狼(43225570)
武大,你看到了么?

2005-02-01 16:15:49 乾隆(7891551)
我今天换了个QQ代理速度快了N多

2005-02-01 16:15:53 A3.武稀松(42088303)
[?]

2005-02-01 16:16:03 B6.银狼(43225570)
刚才我帖的大图,

2005-02-01 16:16:17 B6.银狼(43225570)
是D7里的,不知道怎么出来的

2005-02-01 16:16:25 B6.银狼(43225570)
我不喜欢它

2005-02-01 16:16:39 A3.武稀松(42088303)
大概B6安装了什么第三方的OTA工具

2005-02-01 16:16:49 B6.银狼(43225570)
OTA?

2005-02-01 16:17:18 B6.银狼(43225570)
以前没有的,就是今天和D10远程时,搞出来的

2005-02-01 16:17:26 D10.天地弦(185511468)
[:L]

2005-02-01 16:17:26 A3.武稀松(42088303)
Open Tools Api Delphi的IDE开发接口

2005-02-01 16:17:36 B6.银狼(43225570)
不知道怎么弄的

2005-02-01 16:17:54 D10.天地弦(185511468)
format c:/q
F:

2005-02-01 16:18:04 D10.天地弦(185511468)
cd system\win98

2005-02-01 16:18:03 B6.银狼(43225570)
A3.武稀松(42088303) 16:17:26
Open Tools Api Delphi的IDE开发接口 〈--没懂

2005-02-01 16:18:08 D10.天地弦(185511468)
setup 

2005-02-01 16:18:07 A3.武稀松(42088303)
[shake]

2005-02-01 16:18:09 B6.银狼(43225570)

2005-02-01 16:18:19 B6.银狼(43225570)
[xx]

2005-02-01 16:18:39 D10.天地弦(185511468)
[:L]

2005-02-01 16:18:42 D10.天地弦(185511468)
错了

2005-02-01 16:19:00 D10.天地弦(185511468)
cd system\win2k\i386

2005-02-01 16:19:03 D10.天地弦(185511468)
winnt

2005-02-01 16:20:04 D10.天地弦(185511468)
3哥,把你的记录传我一份

2005-02-01 16:20:13 D10.天地弦(185511468)
中间死了两次

2005-02-01 16:20:13 A3.武稀松(42088303)
等下

2005-02-01 16:20:28 D10.天地弦(185511468)
我整理上传

2005-02-01 16:21:25 D8 。飘尘(43745429)
记录给偶了

2005-02-01 16:21:40 A3.武稀松(42088303)
怎么导出从一定时间一后的记录

A3.武稀松(42088303) 16:30:23
我怀疑优化编译的时候最后一个调用的控件方法以后EAX没有被还原,所以再次调用那个没有被创建的类的的时候EAX还是以前的值,也就是对象是上一个被调用的对象.

B1.斜阳(249208513) 16:30:57
在Delphi中生成的汇编中,通常总是用EBX暂存Eax中的内容

A3.武稀松(42088303) 16:31:10


B1.斜阳(249208513) 16:31:49
而EBX通常不参与参数的传递,这样,在进入某一个函数的时候,ebx寄存器中的内容,有可能是上一个函数中的self

B2.TCP INFO(31329846) 16:32:11
这里 看到没

B2.TCP INFO(31329846) 16:32:22
[调试图片]
 
B2.TCP INFO(31329846) 16:32:43
mov eax,ebx

A3.武稀松(42088303) 16:32:44
但是如果编译优化选项去掉为什么就会报错

B1.斜阳(249208513) 16:32:47
不清楚Delphi怎么优化的,当声明一个类类型的变量的时候,都是用push ebx,而不是push 00

D8 。飘尘(43745429) 16:33:59
当声明一个类类型的变量的时
一个类类型?????

A3.武稀松(42088303) 16:34:09
类类型的变量

B1.斜阳(249208513) 16:34:17
这就倒是在临时变量的堆栈中,对于类类型的,其初值不是nil

A3.武稀松(42088303) 16:34:27


A3.武稀松(42088303) 16:34:44
我想B1说得是最正确地


B1.斜阳(249208513) 16:35:00

类型->数据类型是类的变量

B1.斜阳(249208513) 16:35:41
而因为在Delphi为类类型变量准备堆栈的时候是用push ebx


A3.武稀松(42088303) 16:35:42
类类型的变量很准确,


A3.武稀松(42088303) 16:36:30
B1说得对
B1.斜阳(249208513) 16:36:47
因此,在没有对ebx的内容进行修改的前提下,在引用堆栈中的类类型变量的时候,自然是直接使用ebx要不从堆栈中再计算一次要快

A3.武稀松(42088303) 16:36:47
应该是push ebx这里出的问题

B1.斜阳(249208513) 16:37:15
因此,在类试
var
  a: TForm;
begin
  ShowMessage(a.Caption)
end;
 
B1.斜阳(249208513) 16:37:20
这样的代码中

A3.武稀松(42088303) 16:38:01
A是上一个被调用对象

B1.斜阳(249208513) 16:38:20
对a.Caption的调用,其中的a这个标号,不是从堆栈中计算出来的一个地址,而是直接引用ebx中的内容

B1.斜阳(249208513) 16:38:31
呵呵,这是我的理解

B1.斜阳(249208513) 16:39:37
Button1Click这个函数虽然是Form中的函数,但是,却是Button1的事件响应函数,因此,这个函数是从Tbutton中调用的

D10.天地弦(185511468) 16:42:08
A3.武稀松(42088303) 16:30:23
我怀疑优化编译的时候最后一个调用的控件方法以后EAX没有被还原,所以再次调用那个没有被创建的类的的时候EAX还是以前的值,也就是对象是上一个被调用的对象. ==>我也这样认为

A3.武稀松(42088303) 16:40:29
B1.斜阳(249208513) 16:39:37
Button1Click这个函数虽然是Form中的函数,但是,却是Button1的事件响应函数,因此,这个函数是从Tbutton中调用的
----------------------------------------
最后一个被调用到的对象是Button1

B1.斜阳(249208513) 16:40:45
是的