Указатель ^ Pchar на массив PChar - PullRequest
1 голос
/ 27 марта 2019

при переходе с Delphi 6 на Delphi 10.2 Tokyo я получаю сообщение об ошибке, когда пытаюсь привести указатель ^ PChar к массиву PChar

type
  PServEnt = ^TServEnt;
  TServEnt = packed record
    s_name: PChar;                 // official service name
    s_aliases: ^PChar;             // alias list
    s_port: Smallint;              // protocol to use
    s_proto: PChar;                // port #
  end;

function TIdStackWindows.WSGetServByPort(
  const APortNumber: Integer): TIdStrings;
var
  ps: PServEnt;
  i: integer;
  p: array of PChar;
begin
  Result := TIdStringList.Create;
  p := nil;
  try
    ps := GetServByPort(HToNs(APortNumber), nil);
    if ps <> nil then
    begin
      Result.Add(ps^.s_name);
      i := 0;
      p := Pointer(ps^.s_aliases); // get error Incompatible types: 'Dynamic array' and 'Pointer' 
      while p[i] <> nil do
      begin
        Result.Add(PChar(p[i]));
        inc(i);
      end;
    end;
  except
    Result.Free;
  end;
end;

этот код хорошо работает на Delphi 2010, как его сделатьисправить в Delphi 10.2 Токио

1 Ответ

4 голосов
/ 27 марта 2019

Сообщение об ошибке является правильным, и если код, скомпилированный в более ранних версиях Delphi, был вызван недостатком этих более ранних версий компилятора.

Динамический массив - это больше, чем просто указатель на первыйэлемент.Он также инкапсулирует метаданные, в которых хранится длина массива и счетчик ссылок.Таким образом, ваш актерский состав недействителен.Вы получили этот неверный код, потому что не пытались получить доступ к этим метаданным, но это так же случайно, как и по намерению.

Не пытайтесь привести к динамическому массиву.Вместо этого используйте арифметику указателя.Например:

function TIdStackWindows.WSGetServByPort(
  const APortNumber: Integer): TIdStrings;
var
  ps: PServEnt;
  p: PPChar;
begin
  Result := TIdStringList.Create;
  try
    ps := GetServByPort(HToNs(APortNumber), nil);
    if ps <> nil then
    begin
      Result.Add(ps^.s_name);
      p := PPChar(ps^.s_aliases); // cast needed due to Indy record type's use of un-nameable type
      while p^ <> nil do
      begin
        Result.Add(p^);
        inc(p);
      end;
    end;
  except
    Result.Free;
    raise;
  end;
end;

Я изменил объявление типа списка псевдонимов на PPChar, чтобы избежать несовместимых ошибок типа при назначении локальной переменной этого типа.

Обратите внимание, что я исправил вашу обработку исключений, которая ранее поглощала исключения и возвращала недопустимую ссылку на объект.

...