Подсказка компилятора: "Встроенная функция"... "не была расширена..."

В блоке я использую функцию DeleteFile, и компилятор выводит подсказку:

"H2443 Встроенная функция 'DeleteFile' не была расширена, потому что единица 'Windows' не указана в списке USES

В Uses существует SysUtils, который определяет DeleteFile (хотя внутренний вызов Windows.DeleteFile).

Что означает этот намек? Если я поместил Windows в предложение Uses, оно исчезло, но я хотел бы понять, что это заставляет компилятор беспокоиться.

Ответ 1

Это ограничение вложения.

См. статью Hallvard Vassbotn о Вложенные процедуры.

Извлечен из этого сайта:

Остальные ограничения вложения являются общими для обеих платформ и наиболее важными являются

  • отсутствие вставки границ пакетов
  • встроенная процедура не может получить доступ к идентификаторам раздела реализации
  • сайт вызова должен иметь доступ ко всем идентификаторам, используемым в inlined рутина

Примечание. Последняя точка означает, что, если блок узла вызова не использует единицы, требуемые подпрограммой, подпрограмма не может быть встроена. Когда это произойдет, компилятор выдает подсказку вроде этого

 [Pascal Hint] InlinedRoutinesU.pas(14): H2443 Inline function 
   'InlineMe' has not been expanded because unit 'RequiredUnit' 
    is not specified in USES list 
     

Чтобы устранить проблему, добавьте отсутствующее имя элемента в предложение использования сайта вызова.

Ответ 2

Встроенные функции могут быть расширены встроенными. Например:

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.

Это устраняет накладные расходы на вызов функции.

Но для того, чтобы заменить вызов телом функции, компилятору нужна дополнительная информация, следовательно, жалоба на устройство.

Помните, что не все встроенные функции преобразуются. Некоторые рассматриваются как обычные функции (вплоть до компилятора). Кроме того, inline нужен только при очень узких узких узких местах.

Ответ 3

Я тоже был смущен этим намеком. Тогда я понял, в чем проблема. Ваш код:

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' не была расширена, потому что единица 'Windows' не указана в списке USES

Ответ 4

Встроенные функции расширяются на месте компилятором, избегая накладных расходов на вызов функции. Например. для квадратизации sqr (x) скомпилируется как x * x, а не вызывает функцию, которая умножает x и возвращает результат.