PChar/PWideChar/PAnsiChar强制转换中有编译器的魔力吗



我经常读到编译器在转换为PChar时会发挥某种魔力。

PChar的主要用途是调用库中的外部代码,这些代码需要一个以零结尾的字符数组(C风格的"字符串")。

PChar是一种类型,在Unicode Delphi上是PWideChar的别名,在非Unicode Delphi中是PAnsiChar的别名。

另一方面,Delphi字符串(string=AnsiString/UnicodeString,我在这里不是在谈论WideString,更不用说ShortString了…)具有隐藏长度,而不是终止字符。它们也被引用计数,并使用写时复制。

Delphi字符串是自动分配并保持为一个字符长,带有隐式#0字符,以便更容易转换为PChar(PAnsiChar/PWideChar),还是编译器在遇到转换为PChar时检查并调整字符串?

过程如下:

  • 如果字符串s的长度大于零,则PChar(s)返回指向字符串内容的第一个元素的指针。因为string被管理为具有隐藏的空终止符,所以不需要再做任何事情
  • 如果字符串s的长度为零,则PChar(s)返回一个指向包含空终止符的内存块的指针

作为实现细节,从PChar(nil)返回的null终止符是在编译模块的只读部分中分配的全局常量。

Delphi字符串是否自动分配并保持为一个字符长,带有隐式#0字符,以便更容易转换为PChar(PAnsiChar/PWideChar)?

是的。

神奇之处,如果你可以这么说的话,就是:

  1. 对空字符串使用PChar()会返回一个指向空终止符的指针
  2. Delphi在字符串末尾维护隐藏的null终止符
字符串变量内部是指向包含前缀、字符和null终止符的结构的指针。虽然结构从前缀(包含字符串长度、引用计数、字符大小和代码页)开始,但指针指向第一个字符,因此转换为PChar很简单。

字符串->PChar铸造的神奇之处在于,即使字符串为空(S = ''Pointer(S) = nil),也始终是PChar(S) <> nilPChar(S)不像Pointer(S)那样返回字符串变量指针"原样",而是调用一个函数来检查Pointer(S)是否为零,以及Pointer(S) = nil是否返回指向伪空字符串而不是nil的指针(即指向伪空串的空终止符的指针)。

最新更新