gpt4 book ai didi

delphi - 为什么我不能将过程变量与 nil 进行比较?

转载 作者:行者123 更新时间:2023-12-02 14:03:43 24 4
gpt4 key购买 nike

Anders Melander 的 Drag Drop 套件在 DragDrop.pas 单元中包含以下代码片段:

var
URLMONDLL: THandle = 0;
_CopyStgMedium: function(const cstgmedSrc: TStgMedium; var stgmedDest: TStgMedium): HResult; stdcall = nil;

function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
begin
// ....
if (URLMONDLL = 0) then
begin
URLMONDLL := LoadLibrary('URLMON.DLL');
if (URLMONDLL <> 0) then
@_CopyStgMedium := GetProcAddress(URLMONDLL, 'CopyStgMedium');
end;

if (@_CopyStgMedium = nil) then <<-- E2008 Incompatible types
raise Exception.Create(sNoCopyStgMedium);

Result := (Succeeded(_CopyStgMedium(SrcMedium, DstMedium)));
end;

所有这些变体都可以编译:

if (@@_CopyStgMedium = nil) then  <<-- logical error, is a pointer to the procedural var
if (pointer(@_CopyStgMedium) = nil) then <<-- correct
if not(Assigned(@_CopyStgMedium)) then <<-- correct

为什么我在这里收到 E2008 不兼容类型
请注意,我已将 @ 运算符设置为 true。 {$T+}
但这仍然不能解释为什么我不能与 nil 进行比较,nil 不与任何指针兼容吗?

最佳答案

在我看来,这里使用 @ 运算符是错误的并且没有必要。在我看来,这只会增加困惑。

代码如下:

function CopyStgMedium(const SrcMedium: TStgMedium; var DstMedium: TStgMedium): boolean;
begin
// ....
if (URLMONDLL = 0) then
begin
URLMONDLL := LoadLibrary('URLMON.DLL');
if (URLMONDLL <> 0) then
_CopyStgMedium := GetProcAddress(URLMONDLL, 'CopyStgMedium');
end;

if not Assigned(_CopyStgMedium) then
raise Exception.Create(sNoCopyStgMedium);

Result := (Succeeded(_CopyStgMedium(SrcMedium, DstMedium)));
end;

至于@运算符在这里的作用,它消除了调用函数和引用函数之间的歧义。所以,

if _CopyStgMedium = nil then

无效,因为这是调用该函数的尝试。从表面上看

if @_CopyStgMedium = nil then

应该可以工作,但是因为您输入了地址,所以 @_CopyStgMedium 是一个类型化函数指针,显然与 nil 不具有可比性。如果您愿意,您可以放弃这样的类型:

if Pointer(@_CopyStgMedium) = nil then

但我认为 Assigned 更好。

虽然这很奇怪。 documentation说:

In some situations it is less clear how a procedural variable should be interpreted. Consider the statement:

if F = MyFunction then ...;

In this case, the occurrence of F results in a function call; the compiler calls the function pointed to by F, then calls the function MyFunction, then compares the results. The rule is that whenever a procedural variable occurs within an expression, it represents a call to the referenced procedure or function. In a case where F references a procedure (which doesn't return a value), or where F references a function that requires parameters, the previous statement causes a compilation error. To compare the procedural value of F with MyFunction, use:

if @F = @MyFunction then ...;

@F converts F into an untyped pointer variable that contains an address, and @MyFunction returns the address of MyFunction.

很明显,当启用类型化地址时,@F 不是非类型化指针。如果是这样,那么上面代码中对 Pointer 的强制转换将不会产生任何效果。

因此,本文档与启用键入地址时观察到的行为不符。当启用类型化地址时,@ 在应用于过程类型的表达式时不会产生非类型化指针。 Johan 正确地指出,在旧版本中,例如 XE3,即使启用了类型化地址,@ 也会产生一个非类型化指针。所以也许文档是正确的,但编译器有缺陷。我怀疑是这样的。无论哪种方式,都应该提交错误报告。

关于delphi - 为什么我不能将过程变量与 nil 进行比较?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32550835/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com