@映射方法入口点时的运算符用法

J..*_*... 6 delphi dll

当动态加载DLL时,DoSomething我们可以做一个方法类型变量

 DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
Run Code Online (Sandbox Code Playgroud)

要么

 @DoSomething:= GetProcAddress(MyDLLHandle ,'DoSomething');
Run Code Online (Sandbox Code Playgroud)

在现代版本的Delphi中,这两者似乎表现相同.我的问题是 - @操作员是否总是可选的,如果没有,Delphi的版本是否可选?

该文档指出@,当与例程(函数/过程)类型一起使用时,返回具有类型的函数的入口点Pointer.当直接使用变量时,它自然具有声明的任何特定类型,但也返回该方法的入口点. GetProcAddress返回一个Pointer所以我假设@加载DLL时包含的习惯来自这些不匹配类型不兼容的时间.是这样的吗?

是否有任何合理的论据可以选择这些风格?

Dav*_*nan 5

我不相信自Delphi的原始版本以来发生了任何变化.

官方标题转换GetProcAddress的返回类型FARPROC是无类型Pointer类型的别名.因此,你可以在赋值语句的左侧放置几乎任何指针式的东西,因为当其中一个操作数是时,类型检查会被暂停Pointer.

另一方面,考虑这个程序:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := Proc;
end.
Run Code Online (Sandbox Code Playgroud)

这无法编译:

E2010不兼容的类型:'指针'和'过程,无类型指针或无类型参数'

简单的解决方法是使用@运算符:

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := @Proc;
end.
Run Code Online (Sandbox Code Playgroud)

当然,许多Delphi示例都使用以下方法:

@Proc := GetProcAddress(...);
Run Code Online (Sandbox Code Playgroud)

而不是

Proc := GetProcAddress(...);
Run Code Online (Sandbox Code Playgroud)

我宁愿怀疑这里没有什么深刻的东西.仅仅是作者在第一篇关于该主题的在线文章之一的选择中做出的选择,这些文章在历史上传播并没有充分的理由.这让我想起了动态加载的可怕Rosetta代码示例,该示例测试是否HMODULE大于32,这是一个错误的检查,可以在每周的Stack Overflow问题中看到!

您是否应该@在这些情况下使用?在我看来,你不应该.它没有太大的区别,并且考虑到为什么要打扰一个不必要的标点符号呢?

还有一个我知道你需要使用的场景,@在这种情况下你确实需要@@.考虑以下程序:

{$APPTYPE CONSOLE}

uses
  SysUtils;

var
  Proc: procedure;
  Ptr: Pointer;

begin
  Ptr := @Proc;
  Writeln(Format('%p', [Ptr]));
  Ptr := @@Proc;
  Writeln(Format('%p', [Ptr]));
  Readln;
end.
Run Code Online (Sandbox Code Playgroud)

产量

00000000
00423EBC

第一个赋值获取Proc变量中保存的值,因为它是默认初始化全局变量,为零.第二个赋值获取Proc变量的地址.为此你需要@@.需要这么多间接是非常不寻常的,但在编写与动态链接相关的代码时往往会突然出现.

  • 猴子看猴子做的是一种可爱的方式 (4认同)