delphi的对象机制浅探(编辑修改稿)内容摘要:

=================================================== ⊙ 测试目标:考查 ShortString 返回值类型的函数没有赋值时编译器的实现 ======================================================================== procedure Test。 register。 begin。 lea edx, [ebp$00000100]。 编译器会在堆栈中创建 256 byte 的临时空间,以保证 edx 不会为非法值 mov eax, [$00412eac] call end。 ⊙ 函数代码: class function : ShortString。 {$IFDEF PUREPASCAL} begin Result := PShortString(PPointer(Integer(Self) + vmtClassName)^)^。 end。 {$ELSE} asm { EAX VMT } { EDX Pointer to result string } PUSH ESI PUSH EDI MOV EDI,EDX。 EDX 是返回值串的指针 MOV ESI,[EAX].vmtClassName XOR ECX,ECX MOV CL,[ESI]。 设置 result string 的 length INC ECX REP MOVSB POP EDI POP ESI end。 {$ENDIF} 结论:这只是我想了解字符串返回值的传递方式。 =================== (完 ) =================== 来自: lance2020, 时间: 202013 9:46:00, ID: 2390276 写的非常好。 来自: dedema, 时间: 202013 9:57:00, ID: 2390302 这么厉害啊。 一个晚上就完成了。 来自: 积步 , 时间: 202013 10:10:00, ID: 2390324 mark 来自: zhumoo, 时间: 202013 10:26:00, ID: 2390353 高手就是高手 ,学习 . 来自: kk2020, 时间: 202013 15:05:00, ID: 2390894 楼主一个晚上完成,只能说佩服了。 来自: renyi, 时间: 202013 17:54:00, ID: 2391175 厉害,不知 Delphi 的对象机制和 Java 、 C 相比,哪个个的效率更高。 来自: einsteingod, 时间: 202013 19:07:00, ID: 2391225 写的非常好。 来自: xff916, 时间: 202013 19:49:00, ID: 2391246 牛呀,学习 ,学习,在学习 来自: 积步 , 时间: 202013 19:50:00, ID: 2391248 小弟還有一事不知。 通過 asm訪問類 的私有變量 . TA = class private FA: Integer。 public procedure SetA(Value: Integer)。 end。 var Form1: TForm1。 implementation {$R *.dfm} procedure (Sender: TObject)。 var A: TA。 tmpInt: Integer。 begin A :=。 tmpInt := 0。 (100)。 asm MOV ECX,。 //為什麼 = 100 立即數就可以顯示為 100, 如果不改就顯示 為其它值。 MOV tmpInt, ECX。 end。 ShowMessage(IntToStr(tmpInt))。 end。 来自: savetime, 时间: 202014 1:30:00, ID: 2391511 to 积步 : DELPHI 对“ MOV ECX, ”生成的代码实际上 是以 Record 的类型生成的,这样 ECX 的值就是 变量 A 的地址 加上 的偏移值,结果是 ECX 变成堆栈上的一个值,所以不对。 的实际地址是 A 指向的地址 (也就是对象内存位置,而不是 A 的地址 )加上 FA 相对于对象 头部的偏移地址。 我凑出以下的代码,可以实现你要的结果: var A: TA。 tmpInt: Integer。 begin A :=。 tmpInt := 0。 (100)。 asm MOV EBX, A MOV ECX, TA(EBX).FA。 // 通知编译器 EBX 指向的是 TA class MOV tmpInt, ECX。 end。 ShowMessage(IntToStr(tmpInt))。 end。 我没写过汇编代码,所以不知道 DELPHI 会不会自动保护其他使用 EBX 的语句。 如果你知道在混合 汇编的情况下如何使用寄存器请教我一下。 其实我真的不知道还有这种方法可以获得私有成员,有趣。 来自: savetime, 时间: 202014 2:40:00, ID: 2391532 内容更正: 我发现自己在上文注释中的一个错误,在以下汇编第三行的“ push ecx ”我把它注释为 “保存 ecx (无用的语句 )”, 更正为: “分配局部变量 Obj 的堆栈空间”。 原来 add esp, $4 花费 3 个字节的指令 而 push ecx 只要 1 个字节的指令,执 行更快 大家现在知道我不是高手了吧,我是一边翻汇编手册,一边写注释的。 我只能毫不谦虚地 说:我真的是初学者。 高手看这些简单的汇编代码哪里需要花一个晚上。 希望大家关注内容,不要只是说“好”,重要的是“有没有错误”,这样才能提高。 出错的注释段: ================================================= ⊙ 测试目标:查看 的编译器实现 ================================================= ⊙ 测试代码及反汇编代码: procedure Test。 register。 var Obj: TObject。 begin push ebp。 前 2 句用于设置堆栈指针 mov ebp, esp push ecx。 保存 ecx (无用的语句 ) (更正为 ) 分配局部变量 Obj 的堆栈空间 Obj :=。 mov dl, $01。 设置 dl = 1,通知 这是一次新建对象的调用 mov eax, [$004010a0]。 把指向 TObject class VMT 的指针存入 eax,。 作为 隐含的 Self 参数 call。 调用 函数 mov [ebp$04], eax。 返回新建对象的指针至 Obj end。 pop ecx。 恢复堆栈并返回 pop ebp ret 来自: savetime, 时间: 202014 2:40:00, ID: 2391533 to 积步 , 我测试了在混合汇编的情况下修改寄存器时的实现,结果是: Delphi 会自动把嵌入汇编中修改了的寄存器备份在堆 栈中,所以可以随意使用 Delphi 允许的寄存器。 来自: book523, 时间: 202014 10:20:00, ID: 2391614 结论:真是精妙。 一个对象的正常的创建 (Obj := , 与后面不正常的调用相对 )过程是这样的: 1. 编译器保证第一个 constructor 调用之前 dl = 1 编译器保证 inherited Create 调用之前 dl = 0 2. dl = 1 时 编译器保证 Create 时 eax = pointer to class VMT dl = 0 时 编译器保证 Create 时 eax = pointer to current object 3. 编译器保证任何层次的 constructor 调用后 eax = pointer to current object 4. dl = 1 时 编译器保证 Create 调用 ,并与 constructor 相同的方式使用 eax dl = 1 时 编译器保证 Create 调用 ,并且调用前后 eax = pointer to current object dl = 0 时 编译器保证 Create 不会调用 dl = 0 时 编译器保证 Create 不会调用 5. 中设置结构化异常处理,在 Create 即将结束时关闭结构化异常处理。 如果出错则会 (1)释放由编译器分配的内存 (2)恢复堆栈至创建对象之前 (3)调用。 看上去有点繁杂,可是如果读懂了上面 和 则会感觉对象的创建非常清晰。 为什么要保存经常调用 dl 的值。 Dl 主要用来表示是 class 级别调用还是对象级别调用, class 级别调用时, constructor 会自动执行 , NewInstance,InitInstance, AfterConstruction 等过程, 然后才是 Constructor 中的代码, 而对象级别调用时,只会执行 Constructor 中的代码。 来自: savetime, 时间: 202014 12:18:00, ID: 2391785 to book523, 你说的是我在“⊙测试目标:以 object reference 和 class reference 调用构造函数的编译器实现”中的结果吧。 我在文章中写的结论是:“ object reference 方式的 constructor 调用,编译器尝试实现为 inherited 调用” 其实如果你看了测试代码的反汇编过程,就应该知道我的这个结论是错误的。 Borland 在 Object Pascal Reference 中写的就是你说的“对象级别调用时,只会执行 Constructor 中的代码。 ”,可是事实上不是这样。 在形式如下的代码中 AComp := Borland 先将 edx 所有 bit 设置为 1 ,也就是 dl 为 1,也就是仍然尝试沿用 class 级别的调用。 可是你看 Delphi 的生成的汇编代码不知所云,所以根本就没有所谓的“对象级别调用”。 我认为 Borland 应该对 AComp := 调用提示为语法错误。 我实在是想不到什么时候会需要这种形式的调用。 我测试这样的调用方式是因为我经常在创建 Form 时忘了写 T 这一标识符: ChildForm := (nil)。 // 这里应该是 (nil) 我想知道这样的结果是什么。 来自: vc_delphi, 时间: 202014 18:27:00, ID: 2392395 高手就是高手 ,学习 . 来自: 积步 , 时间: 202014 21:30:00, ID: 2392563 to savetime: 多謝指教。 以前也研究過匯編什麼東東的。
阅读剩余 0%
本站所有文章资讯、展示的图片素材等内容均为注册用户上传(部分报媒/平媒内容转载自网络合作媒体),仅供学习参考。 用户通过本站上传、发布的任何内容的知识产权归属用户或原始著作权人所有。如有侵犯您的版权,请联系我们反馈本站将在三个工作日内改正。