delphi - 为什么这个 PAnsiChar 在转换为 AnsiString 时会被截断?

标签 delphi delphi-2010 delphi-xe3

请考虑以下程序:

program SO41175184;

{$APPTYPE CONSOLE}

uses
  SysUtils;

function Int9999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString(IntToStr(9999)));
end;

function Int99999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString(IntToStr(99999)));
end;

function Int999999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString(IntToStr(999999)));
end;

function Str9999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString('9999'));
end;

function Str99999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString('99999'));
end;

function Str999999: PAnsiChar;
begin
  Result := PAnsiChar(AnsiString('999999'));
end;

begin
  WriteLn(Int9999); // '9999'
  WriteLn(Int99999); // '99999'
  WriteLn(Int999999); // '999999'

  WriteLn(string(AnsiString(Str9999))); // '9999'
  WriteLn(string(AnsiString(Str99999))); // '99999'
  WriteLn(string(AnsiString(Str999999))); // '999999'

  WriteLn(string(AnsiString(PAnsiChar(AnsiString(IntToStr(9999)))))); // '9999'
  WriteLn(string(AnsiString(PAnsiChar(AnsiString(IntToStr(99999)))))); // '99999'
  WriteLn(string(AnsiString(PAnsiChar(AnsiString(IntToStr(999999)))))); // '999999'

  WriteLn(string(AnsiString(Int9999))); // '9999'
  WriteLn(string(AnsiString(Int99999))); // '9999' <----- ?!
  WriteLn(string(AnsiString(Int999999))); // '999999'

  ReadLn;
end.

只有在其中一种情况下,字符串才会丢失单个字符,在 Delphi 2010 和 Delphi XE3 中都是如此。对于 FPC,相同的程序可以正常工作。切换到 PChar 也会使问题消失。

我认为这与内存管理有关,但我没有足够的线索去哪里进行有意义的调查。谁能解释一下吗?

最佳答案

动态创建的字符串会进行引用计数,并在没有引用剩余时释放。

Result := PAnsiChar(AnsiString(IntToStr(99999)));

导致创建临时AnsiString,其地址通过转换为PAnsiChar获取,然后释放临时字符串。生成的指针指向现在未声明的内存,该内存可能会因几乎任何原因而被覆盖,包括在分配更多字符串期间。

默认情况下,Delphi 和 FPC 都不会在释放期间清除内存,因此,如果内存尚未重新使用,那么在读取曾经存在的内容时,您可能会很幸运。或者,正如您所看到的,您可能不会。

当像这样返回PAnsiChar时,调用者和被调用者之间需要就内存管理达成一致。您需要确保不会过早释放内存,并且您需要确保调用者知道如何在之后释放内存。

Remy Lebeau 指出,这种释放发生在过程或函数返回时。如果在对 Result 赋值之后还有其他语句,则该字符串仍然可用。这通常是正确的,但也有一些情况是临时字符串在返回之前被释放,例如当您在循环中创建临时字符串时。我不建议在创建临时对象的语句结束后使用临时对象,即使它是有效的,因为这使得验证代码是否正确变得非常困难。对于这些情况,只需使用显式变量即可。

关于delphi - 为什么这个 PAnsiChar 在转换为 AnsiString 时会被截断?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41175184/

相关文章:

delphi - Delphi-2010 中仍然需要 FastShareMem 吗?

delphi - 编译完包后在哪里可以找到 bpl 文件?

delphi - 如果调用 FastReport.PrepareReport,则 ISAPI Web 应用程序挂起

c - 将 C .obj 文件链接到 Delphi 应用程序,解析标准 C 依赖项

delphi - 印地10 + OpenSSL : send email code stopped working on Windows 8

delphi - Oracle - 存储过程不是比应用程序内查询更受青睐吗?

delphi - 如何让 FastReport 生成可在 iOS 上查看的 PDF?

delphi - 如何用Delphi计算当前日期的日出和日落时间

android - 如何更改 GCM 推送通知的样式

delphi - 何时调用单元中的终结方法?