在一个单元中,我使用函数DeleteFile
,编译器输出一个提示:
“H2443内联函数'DeleteFile'尚未展开,因为在USES列表中未指定单位'Windows'”
在Uses
中有SysUtils
,其中定义DeleteFile
(虽然内部调用Windows.DeleteFile
)。
这个提示意味着什么?如果我将Windows
放入Uses
子句中,它已经消失了,但我想了解困扰编译器的是什么。
答案 0 :(得分:24)
这是一个内联限制。
见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子句中。
答案 1 :(得分:11)
内联函数可以内联扩展。例如:
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.
这消除了函数调用的开销。
但是为了用函数体替换调用,编译器需要更多的信息,因此关于单元的抱怨。
请注意,并非所有内联函数都已转换。有些被视为普通函数(由编译器决定)。此外,仅在非常严格的性能瓶颈时才需要内联。
答案 2 :(得分:7)
我也被这个提示弄糊涂了。然后我意识到问题是什么。你的代码:
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;
如果您发现,&#34;新&#34; 代码取决于WinApi.Windows
单位:
Result := Winapi.Windows.DeleteFile(PChar(FileName));
您没有在uses
条款中加入。
如果您手动内联代码(复制并粘贴),则在将Windows
添加到uses
之前,代码将无法编译。
相反,编译器不会执行inline
因为:
内联功能&#39;删除文件&#39;尚未扩展,因为单位&#39; Windows&#39;未在USES列表&#34;
中指定
答案 3 :(得分:1)
内联函数由编译器扩展到位,避免了函数调用的开销。例如。对于平方,sqr(x)以x * x编译,而不是调用与x相乘的函数并返回结果。