为什么Format拒绝以XE4开头的过程地址参数

时间:2014-09-12 20:01:31

标签: delphi

考虑这个程序:

{$APPTYPE CONSOLE}

uses
  System.SysUtils;

procedure Foo;
begin
end;

type
  TProcedure = procedure;

const
  FooConst: TProcedure = Foo;

var
  FooVar: TProcedure = Foo;
  P: Pointer;

{$TYPEDADDRESS ON}

begin
  P := @Foo;
  Writeln(Format('%p', [P]));
  Writeln(Format('%p', [@FooConst]));
  Writeln(Format('%p', [@FooVar]));
  Writeln(Format('%p', [@Foo]));
  Readln;
end.

该程序在XE3上编译并运行,并产生以下输出:

00419FB8
00419FB8
00419FB8
00419FB8

在XE4及更高版本上,程序无法编译,并且在以下两行中都有错误消息:

Writeln(Format('%p', [@FooConst]));
Writeln(Format('%p', [@FooVar]));
[dcc32 Error] E2250 There is no overloaded version of 'Format' that can be called
with these arguments

在XE4,XE5和XE6上,程序在$TYPEDADDRESS关闭时编译。在XE7上,无论$TYPEDADDRESS

的设置如何,程序都无法编译

这是编译器错误吗?或者我使用不正确的语法来获取过程的地址?

2 个答案:

答案 0 :(得分:4)

我认为这是一个编译器错误,并提交了质量控制报告:QC#127814

作为解决方法,您可以使用以下任一方法:

  1. 使用addr()而不是@运营商。
  2. @FooVar@FooConst投放到Pointer,例如Pointer(@FooVar)

答案 1 :(得分:1)

我认为新编译器XE7的行为与规范更加一致,并且在这种情况下需要显示错误,因为{$TYPEDADDRESS ON}强制@运算符返回一个类型指针而Format函数则将非类型泛型指针作为输入。

由于{$TYPEDADDRESS ON}的目的是鼓励小心使用指针,在编译时捕获不安全的指针赋值,如果函数需要一个通用的无类型指针(,在这种情况下make感觉因为函数的目的是打印它的地址 - 所以不需要有类型指针来检索它的地址),编译器会在传入类型指针的情况下捕获错误,行为是一致的与规范。

我认为在这种情况下,正确的方法(基于文档)将是:

  Writeln(Format('%p', [Addr(FooConst)]));
  Writeln(Format('%p', [Addr(FooVar)]));

因为Addr函数总是返回一个无类型的指针,它是Format %p所期望和需要的指针。

我假设在以前的版本中,编译器在这种情况下用于执行自动转换:Pointer(@FooConst),但由于{{{$TYPEDADDRESS ON}它没有太多意义。 1}}指令。