procedure Run(Proc: TProc); begin Proc; end; procedure Test; begin Run( procedure var S: PChar; procedure Nested; begin Run( procedure begin end); S := 'Hello,world!'; end; begin Run( procedure begin S := 'Hello'; end); Nested; ShowMessage(S); end); end;
对我来说会发生什么呢S:=’你好,世界!存储在错误的位置。因此,引发访问冲突,或ShowMessage(S)显示“Hello”(有时候,释放用于实现匿名过程的对象时会引发访问冲突)。
我使用的是Delphi XE,所有更新都安装了。
我怎么知道这会造成什么问题?我知道如何重写我的代码以避免匿名过程,但我无法确定哪些情况导致错误的代码,所以我不知道在哪里避免它们。
如果这是在Delphi的后期版本中修复的,那么有趣的是,在这一点上升级不是一个选择。
在QC上,最近的报告我可以找到类似的#91876,但是在Delphi XE中解决了。
更新:
... procedure Nested; begin Run( procedure begin S := S; end); S := 'Hello,world!'; end; ...
工作。
S := 'Hello,world!';
在失败的程序是
ScratchForm.pas.44: S := 'Hello,world!'; 004BD971 B89CD94B00 mov eax,$004bd99c 004BD976 894524 mov [ebp+$24],eax
而正确的版本是
ScratchForm.pas.45: S := 'Hello,world!'; 004BD981 B8B0D94B00 mov eax,$004bd9b0 004BD986 8B5508 mov edx,[ebp+$08] 004BD989 8B52FC mov edx,[edx-$04] 004BD98C 89420C mov [edx+$0c],eax
失败的程序中生成的代码没有看到S被移动到编译器生成的类,[ebp $ 24]是如何访问嵌套方法的外部局部变量如何访问局部变量。
解决方法
所以似乎S:= S或S:=”导致编译器自己创建引用,甚至可以分配一些内存,这将解释为什么它的工作原理。
我也假设这是为什么一个访问冲突发生没有S:= S或S:=”,因为如果没有为String分配的内存(记住你只声明了S:PChar),则会引发访问冲突,因为未分配已访问内存
如果您只是简单地声明S:String,这可能不会发生。
PChar只是数据结构指针,必须存在。 PChar的另一个常见问题是声明本地变量,然后将PChar传递给该变量到其他Procs,因为发生了什么是本地变量在程序结束后被释放,但PChar仍然会指向它,然后提高访问一次访问冲突。
每个文档存在的唯一可能性就是声明像这样的const S:PChar =’Hello,world!这是因为编译器可以解析一个相对的Adresse。但这仅适用于常量,而不适用于上述示例中的变量。像上面的例子一样,需要将存储分配给PChar所指向的字符串文字,如S:String; P:PChar S:=’你好,世界! P:= PChar(S);或类似物。
如果它仍然失败,声明String或整数,那么也许该变量消失在某处,或突然在proc中不可见,但这将是与现有PChar问题无关的另一个问题。
定论:
可以做S:PChar S:=’你好,世界!但是编译器然后简单地将其分配为局部或全局常量,如const S:PChar =’Hello,world!确实被保存到可执行文件中,第二个S:=’Hello’然后创建另一个也保存到可执行文件中,等等 – 但是S只指向最后一个分配,所有其他仍然在可执行但不可访问不知道确切的位置,因为S只指向最后一个分配。
所以取决于哪一个是最后一个S指向你好,世界!或者你好在上面的例子中,我只能猜测哪一个是最后一个,谁知道编译器也只能猜测,并且取决于优化和其他不可预测的因素S可以突然指向未分配的Mem而不是最后一个由Time Showmessage(S)被执行,然后引发访问冲突。