Delphi 为什么这一个潘斯卡在转换成AnsiString时会被切碎? 请考虑以下程序: 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. 程序SO41175184; {$APPTYPE控制台} 使用 SysUtils; 函数Int9999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(9999)); 结束; 函数Int99999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(99999)); 结束; 函数Int999999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(999999)); 结束; 函数Str9999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('9999')); 结束; 函数Str99999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('99999')); 结束; 函数Str999999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('999999')); 结束; 开始 WriteLn(Int9999);/'9999' WriteLn(Int99999);/'99999' WriteLn(Int999999);/'999999' WriteLn(字符串(AnsiString(Str9999));/'9999' WriteLn(字符串(AnsiString(Str99999));/'99999' WriteLn(字符串(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(9999999‘‘‘‘)’);/'999999' WriteLn(字符串(AnsiString(Int9999));/'9999' WriteLn(字符串(AnsiString(Int99999));/'9999'

Delphi 为什么这一个潘斯卡在转换成AnsiString时会被切碎? 请考虑以下程序: 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. 程序SO41175184; {$APPTYPE控制台} 使用 SysUtils; 函数Int9999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(9999)); 结束; 函数Int99999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(99999)); 结束; 函数Int999999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString(IntToStr(999999)); 结束; 函数Str9999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('9999')); 结束; 函数Str99999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('99999')); 结束; 函数Str999999:PAnsiChar; 开始 结果:=PAnsiChar(AnsiString('999999')); 结束; 开始 WriteLn(Int9999);/'9999' WriteLn(Int99999);/'99999' WriteLn(Int999999);/'999999' WriteLn(字符串(AnsiString(Str9999));/'9999' WriteLn(字符串(AnsiString(Str99999));/'99999' WriteLn(字符串(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(9999999‘‘‘‘)’);/'999999' WriteLn(字符串(AnsiString(Int9999));/'9999' WriteLn(字符串(AnsiString(Int99999));/'9999',delphi,delphi-2010,delphi-xe3,Delphi,Delphi 2010,Delphi Xe3,动态创建的字符串在没有剩余引用时进行引用计数和释放 Result := PAnsiChar(AnsiString(IntToStr(99999))); 导致创建一个临时的AnsiString,其地址通过转换为PAnsiChar,然后临时字符串被释放†。结果指针指向现在无人认领的内存,这些内存可能会因为几乎任何原因被覆盖,包括在分配更多字符串的过程中 默认情况下,Delphi和FPC都不会在释放过程中清除内存,因此如果内存尚未重新使用,那么在读取以前的内存时,您可能会幸运。或者,正如你所看到的,

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

Result := PAnsiChar(AnsiString(IntToStr(99999)));
导致创建一个临时的
AnsiString
,其地址通过转换为
PAnsiChar
,然后临时字符串被释放†。结果指针指向现在无人认领的内存,这些内存可能会因为几乎任何原因被覆盖,包括在分配更多字符串的过程中

默认情况下,Delphi和FPC都不会在释放过程中清除内存,因此如果内存尚未重新使用,那么在读取以前的内存时,您可能会幸运。或者,正如你所看到的,你可能不会

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


†Remy Lebeau指出,当程序或函数返回时,就会发生这种释放。如果在分配给
结果
之后还有另一条语句,则该字符串仍然可用。这通常是正确的,但也有在返回之前释放临时字符串的情况,例如在循环中创建临时字符串时。我不建议在创建临时对象的语句结束后使用临时对象,即使在它有效的情况下也是如此,因为这会使验证代码是否正确变得太困难。对于这些情况,只需使用一个显式变量。

我可以理解这种推理,但我仍然感到好奇,为什么它只发生在其中一个值上。它发生在我的示例程序中,与我正在调试的程序中完全相同。例如,我希望它有时能工作,有时不能。什么能解释这种一致性和值之间的差异呢?@ThijsvanDien分配器很难预测,但相当确定。如果它在程序的一次执行中以某种方式运行,那么它很有可能在所有执行中都以这种方式运行。另外一点是“9999”的长度是4的小倍数。内存块通常与4字节边界对齐,这就解释了为什么部分覆盖会覆盖第五个字符。@Remy不应将不开始句子的单词大写。返回指针的函数应该关心所有的调用者,因此应该保持复数形式。您关于具体何时发生释放的说明是一个很好的说明,当我可以做一些额外的测试时,我会尝试将其带回来。@Thijs:这是未记录的行为,所以任何事情都可能发生,您很幸运,其他函数调用显示了您期望的结果。行为尚未确定,但并非完全未确定。它仅仅取决于同一个内存管理器如何管理相同的分配和释放顺序,即使在不同的系统上也是如此。这可能与不同版本的编译器或不同的内存管理器不同。@ThijsvanDien-尝试将随机行为转化为确定性行为。1) 将Delphi Memory Manager更新至最新版本,从2)将更新后的单元用作测试项目的第一个单元3)在FastMM4Options.inc内启用{.$define AlwaysClearFreedMemory}选项4)构建项目并查看它现在的工作方式,即禁止在空闲后使用内容