Delphi 为什么Format拒绝以XE4开头的过程地址参数
考虑一下这个计划:Delphi 为什么Format拒绝以XE4开头的过程地址参数,delphi,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(For
{$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
[dcc32错误]E2250没有可调用的“格式”重载版本
有了这些论点
在XE4、XE5和XE6上,当关闭$TYPEDADDRESS
时,程序将编译。在XE7上,无论设置了$TYPEDADDRESS
,程序都无法编译
这是一个编译器错误吗?还是我使用了不正确的语法来获取过程的地址?我认为新编译器XE7的行为更符合规范,在这种情况下需要显示错误,因为
{$TYPEDADDRESS ON}
强制执行@
运算符返回一个类型化指针,而Format函数将获取一个非类型化的通用指针作为输入
由于{$TYPEDADDRESS ON}
的目的是鼓励谨慎使用指针,在编译时捕获不安全的指针赋值,因此如果函数需要一个通用的非类型指针,这是正确的(在这种情况下是有意义的,因为函数的目的是打印它的地址-因此不需要类型化指针来检索它的地址),如果类型化指针被传递,编译器将捕获错误,行为与规范一致
我认为在这种情况下,正确的做法(根据文件)是:
Writeln(Format('%p', [Addr(FooConst)]));
Writeln(Format('%p', [Addr(FooVar)]));
因为Addr
函数总是返回一个非类型指针,这正是格式和%p
所期望和需要的
我假设在以前的版本中,编译器(在这种情况下)用于执行自动强制转换:指针(@foocont)
,但由于{$TYPEDADDRESS ON}
指令,它没有太多意义。我认为这是一个编译器错误,并提交了一份质量控制报告:
作为解决方法,您可以使用以下任一方法:
使用addr()
而不是@
运算符
将@FooVar
或@foocont
转换为指针
,例如指针(@FooVar)
Addr(foocont)
和Addr(FooVar)
在XE6中工作。不受$T指令的影响。现在没有XE7。@LURDAddr(…)
也在XE7中编译并正确运行。这很奇怪,指向编译器错误。谢谢.FWIW,指针(@foocont)
在XE6和XE7中也能正常工作。@LURD是的,我已经观察到了,但在你的例子中,它不是一个函数,而是一个引用函数的新类型……没错。但是在这种情况下,我怎么可以将@D
作为格式的参数传递给格式,其中D是一个类型为Integer
或Double
的类型常量或变量或者string
或者record
等等?你的论点也应该适用于那里。你似乎还忽略了,在XE7中,程序在TYPEDADDRESS
设置中都会产生编译器错误。我建议你再次阅读这部分问题。我知道这有点棘手,因为我谈论的是很多不同的compilers的行为都集中在一个问题上。如果错误发生在TYPEDADDRESS关闭的情况下,我们应该在QC Embarcadero中打开一个事件,因为这一次不可能是其他任何错误……它应该与TYPEDADDRESS一起工作,或者不与TYPEDADDRESS一起工作,就像它对任何其他类型一样。FWIW我真的不喜欢在出现错误时回答并接受我自己的答案还有其他答案,但我恐怕不同意@aleroot的分析,我真的相信我上面写的是正确的。应该注意的是,这两种解决方法都隐藏了启用{$TYPEDADDRESS}的目的
,但这是在修复错误之前所能做的最好的事情。@LURD@
在处理过程和过程变量时很奇怪,因为oit被设计为产生非类型指针,如果X是一个变量,@X返回X的地址。(当X是一个过程变量时,特殊规则适用;请参阅如果默认的{$T}编译器指令有效,@X的类型是指针。{$T+}状态下,@X的类型是^T,其中T是X的类型(这种区别对于赋值兼容性很重要,请参阅赋值兼容性).
@LURD是的,这里计算的是引用的其他文档:
[dcc32 Error] E2250 There is no overloaded version of 'Format' that can be called
with these arguments
Writeln(Format('%p', [Addr(FooConst)]));
Writeln(Format('%p', [Addr(FooVar)]));