【问题标题】:Pointer of ^Pchar to array of PChar^Pchar 指向 PChar 数组的指针
【发布时间】:2019-08-18 00:36:32
【问题描述】:

当我从 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 Tokyo 中使其正确

【问题讨论】:

  • 仅供参考,这是非常古老的 Indy 代码。 TIdStringList 在 Indy 中不再存在,它于 2007 年被删除。TIdStackWindows.WSGetServByPort() 在 2010 年针对 Unicode 进行了更新,后来重新编写为 TIdStackWindows.AddServByPortToList()。它的实现与此处显示的完全不同。您需要升级到最新版本的 Indy。
  • 谢谢@RemyLebeau,我用的Indy10自带Delphi 10.2,所有错误都消失了

标签: delphi delphi-10.2-tokyo char-pointer


【解决方案1】:

错误信息是正确的,如果是在早期版本的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,以避免在分配给该类型的局部变量时出现不兼容的类型错误。

另请注意,我已经更正了您之前吞下异常并返回无效对象引用的异常处理。

【讨论】:

  • 感谢您的解决方案,但我在p := ps^.s_aliases; 收到“不兼容的类型”错误,但如果我使用p := Pointer(ps^.s_aliases);,则会出现错误,对此有什么影响吗?
  • 没关系,它只是抑制了严格的类型检查。最好使用PPChar 代替^PChar
  • 谢谢,我用p: PPChar;p := PPChar(ps^.s_aliases); 编译没有错误
  • 将记录字段和局部变量都更改为该类型,您不需要强制转换。尽管如果那是 Indy 类型,那么您将无法使用演员阵容。
  • 仅供参考,getservbyport() 使用 Ansi 字符串返回数据,没有 Unicode 版本,因此您需要在 Delphi 2009+ 中使用 PPAnsiChar 而不是 PPChar
猜你喜欢
  • 1970-01-01
  • 2021-02-07
  • 2016-07-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多