在一个单元中我使用该函数DeleteFile
,编译器输出一个提示:
"H2443内联函数'DeleteFile'尚未展开,因为在USES列表中未指定单位'Windows'"
在Uses
那里SysUtils
,它定义DeleteFile
(虽然内部调用Windows.DeleteFile
).
这个提示意味着什么?如果我Windows
加入该Uses
条款,它已经消失了,但我想了解困扰编译器的是什么.
这是一个内联限制.
请参阅Hallvard Vassbotn关于Inlined Routines的文章.
从该网站提取:
其余的内联限制对于两个平台都是通用的,而最重要的是
没有跨包边界内联
内联例程无法访问实现部分标识符
呼叫站点必须能够访问内联例程中使用的所有标识符
注意最后一点意味着除非调用站点单元使用例程所需的单位,否则不能内联例程.发生这种情况时,编译器会发出这样的提示
[Pascal Hint] InlinedRoutinesU.pas(14): H2443 Inline function 'InlineMe' has not been expanded because unit 'RequiredUnit' is not specified in USES list要解决此问题,请将缺少的单元名称添加到调用站点的uses子句中.
内联函数可以内联扩展.例如:
function AddPlus(const A,B: Integer): Integer; inline; begin Result := A + B + 1; end; var x,y,z : Integer; begin y := 22; z := 11; x := AddPlus(y, z); end.
被重写为:
var x,y,z : Integer; begin y := 22; z := 11; x := y+z+1; end.
这消除了函数调用的开销.
但是为了用函数体替换调用,编译器需要更多的信息,因此关于单元的抱怨.
请注意,并非所有内联函数都已转换.有些被视为普通函数(由编译器决定).此外,仅在非常严格的性能瓶颈时才需要内联.
我也对这个提示感到困惑.然后我意识到问题是什么.你的代码:
uses SysUtils; procedure TForm1.DoStuff; begin SysUtils.DeleteFile('foo'); end;
实际上被替换为:
uses SysUtils; procedure TForm1.DoStuff; var Flags, LastError: Cardinal; begin Result := Winapi.Windows.DeleteFile(PChar(FileName)); if not Result then begin LastError := GetLastError; Flags := GetFileAttributes(PChar(FileName)); if (Flags <> INVALID_FILE_ATTRIBUTES) and (faSymLink and Flags <> 0) and (faDirectory and Flags <> 0) then begin Result := RemoveDirectory(PChar(FileName)); Exit; end; SetLastError(LastError); end; end;
如果您注意到,您的"新"代码取决于WinApi.Windows
单位:
Result := Winapi.Windows.DeleteFile(PChar(FileName));
您未在uses
条款中包含的内容.
如果手动内联代码(复制和粘贴),代码将无法编译,直到您添加Windows
到您的代码uses
.
相反,编译器不会这样做,inline
因为:
内联函数'DeleteFile'尚未展开,因为在USES列表中未指定单位'Windows'