将Delphi 2009/2010字符串文字转换为PAnsiChar

时间:2010-01-05 16:07:41

标签: delphi pointers string

所以问题是Delphi 2009/2010中的字符串文字(或const字符串)是否可以直接转换为PAnsiChar,还是首先需要对AnsiString进行额外的转换才能使其工作?

背景是我在带有C接口的旧DLL中调用函数,该接口具有一些需要C样式char指针的函数。在过去(在Delphi 2009之前),像下面这样的代码就像一个魅力(其中C DLL函数的参数是LPCSTR):

或者:

LegacyFunction(PChar('Fred'));

const
  FRED = 'Fred';
...
LegacyFunction(PChar(FRED));

因此,在更改为Delphi 2009(现在是2010年)时,我将调用更改为:

LegacyFunction(PAnsiChar('Fred'));

const
  FRED = 'Fred';
...
LegacyFunction(PAnsiChar(FRED));

这似乎有效,我从函数调用中得到了正确的结果。然而,应用程序中存在一些明确的不稳定性,这些不稳定似乎主要发生在调用遗留函数的代码中的第二次或第三次(在转移到2009版本的IDE之前不存在)。在研究这个时,我意识到Delphi 2009/2010中的本地字符串文字(和const字符串)是一个Unicode字符串,所以我的演员可能是错误的。此处和其他地方的示例似乎表明此调用看起来应该更像这样:

LegacyFunction(PAnsiChar(AnsiString('Fred')))

令我困惑的是,使用上面第二个示例中的代码,将字符串文字直接转换为PAnsiChar不会生成任何编译器警告。如果不是字符串文字,我正在构建一个字符串var,我会得到一个可疑的强制警告(并且该字符串会被修复)。这(以及字符串在DLL中可用的事实)使我相信编译器正在做一些魔术来正确地将字符串文字解释为预期的字符串类型。这是发生了什么,或者是双重演员(首先是AnsiString,然后是PAnsiChar)真的有必要,而且在我的代码中缺少它是难以追踪不稳定的原因吗?同样的答案也适用于const字符串吗?

4 个答案:

答案 0 :(得分:9)

对于类型推断的常量(只能从文字中初始化),编译器会在编译时更改实际文本,而不是在运行时更改。这意味着知道转换是否会丢失数据,因此如果没有,则不需要发出警告。

答案 1 :(得分:5)

'想象'Barry Kelly和Mason Wheeler的话:

const
  FRED = 'Fred';

var
  p: PAnsiChar;
  w: PWideChar;
begin
  w := PWideChar(Fred);
  p := PAnsiChar(Fred);

In ASM:
Unit7.pas.32: w := PWideChar(Fred);
00462146 BFA4214600       mov edi,$004621a4     
// no conversion, just a pointer to constant/"-1 RefCounted" UnicodeString

Unit7.pas.33: p := PAnsiChar(Fred);
0046214B BEB0214600       mov esi,$004621b0
// no conversion, just a pointer to constant/"-1 RefCounted" AnsiString

正如您在PWideChar / PChar(FRED)和PAnsiChar(FRED)两种情况下所看到的,没有转换,Delphi编译器会生成2个常量字符串,一个AnsiString和一个UnicodeString。

答案 2 :(得分:4)

默认情况下,常量(包括字符串文字)是无类型的,编译器会将它们调整为您正在使用它们的上下文中的任何格式。只要字符串文字中没有非ANSI字符,在这种情况下,编译器不会将字符串生成为ANSI而不是Unicode。

答案 3 :(得分:1)

正如Mason Wheeler指出,只要你在你的字符串const中有非ANSI字符,一切都很好。如果您有以下内容:

const FRED = 'Frédérick';

我很确定Delphi 2009/2010会发出字符集提示(并自动应用字符串转换 - 因此提示)或者在比较时失败('Frédérick'在ISO-8859-1中与UTF-16不同)

如果您的角落中有“特殊”字符,则需要调用字符串转换。

以下是TStringList的一些基本示例:

TStringList.SaveToFile(DestFilename, TEncoding.GetEncoding(28591)); //ISO-8859-1 (Latin1)
TStringList.SaveToFile(DestFilename, TEncoding.UTF8);