为什么在Delphi 7中不能使用PChar('*')?

3
我写了这段代码,但在其中遇到了AV错误。
  procedure TForm1.Button1Click(Sender: TObject);
  Var
     C : Pchar;
     s : string;
 begin
    c:= PChar('*');
    s := string(c); // AV here , but code works if i put C:= PChar('**') 
   ShowMessage(c);
end;

我不知道为什么。有人知道吗?提前感谢。

请具体说明您所说的“AV”是什么意思。 - Security Hound
1
你的代码毫无意义。首先,它是可以工作的。其次,你不需要将其强制转换为“string”。s := c;没有问题,而且ShowMessage(s);ShowMessage(c);同样有效。 - Ken White
1
已编辑了代码,请现在查看。 - Super_User
3个回答

10

用一个单字符的字符串字面量,你是在进行类型转换为Char,而不是string,所以它不是一个指针。当你将它强制转回来时,虽然它声明了类型,但它仍然不是真正的指针,因此它不能被转换为字符串。

如果你发现自己需要对一个字符串字面量进行类型转换,那么你可能在做一些不必要的事情。虽然你可以给它一个提示,让它使用哪种类型,就像这里其他答案所示,但编译器已经能够检测出字面量需要具有的类型,并且通常是正确的。直接把字面量赋值给变量即可,不需要进行任何类型转换。

如果你完全省略了类型转换,那么你的代码将同样适用于任何长度的字符串:

// All PChar assignments, no casting
c := '';
c := '*';
c := '**';

此外,将其转换回 string 是不必要的。您可以直接分配一个 PChar,编译器会自动执行转换。
s := c;

我想知道字符串字面量的分裂症是否有任何记录。我找不到它。似乎'a'是一种类型,而'aa'是另一种类型,这个设计看起来很疯狂。我现在喜欢C语言的字面量语法。 - David Heffernan
@David,我能找到的最好的资料是这里说的:“一个包含一个字符(单字节或多字节)的字符字符串与任何字符类型兼容。”虽然这还不够详细。我通常喜欢 Delphi 的“神奇”字符串字面量。问题通常只会在我们试图在编译器从未需要帮助的情况下“帮助”它时出现,就像这个问题一样。当它不知道正确的类型时,它会发出错误消息。如果它没有这样做,那么我们就不应该进行类型转换。 - Rob Kennedy
这是一个有趣的问题。将PChar(nil)转换为指向空字符的指针的魔法转换非常强大。但是,关于转换的事情是它会抑制错误。责任在于你作为编码人员,你不再有编译器来为你检查。将char或string分配给pchar变量是编译器错误。转换在某些情况下是正确的,但在其他情况下则不是。 - David Heffernan

3
实际上,
c:= PChar('*');

被编译为

mov [c],$0000002a

就像它被写出来的那样:

c:= PChar(ord('*'));

自从 ord('*')=$2a,看来 '*' 字符被强制转换为整数 (NativeInt),然后将此整数转换为指针。因此,当您尝试访问 c 内容时,您实际上是在访问内存地址 $0000002a,这是无效的,并会触发访问冲突。

编译时:

c:= PChar('**');

它是生成的

   mov eax,$00548984
   mov [c],eax

在这种情况下,编译器在可执行文件中生成一个常量#0结尾的文本缓冲区(而不是Delphi的string),并将c设置为它的地址。 PChar('*')不能像char类型一样行为相同,这是一种“优化”,可以将其强制转换为整数。 但我理解这可能会令人困惑。
如果您只想要单个'*'的指针,可以编写以下任一内容:
c:=PChar('*'#0);
c:=PChar(string('*'));

这将按预期工作,因为两者都将绕过转换为字符序数值的强制转换。


1
实际上需要的是 c := '*' - David Heffernan

2

AV指的是与内存不正确的工作。从不存在的位置获取数据或写入到不存在的位置。

问题来自于不同类型的数据。

'*'

是字符,但是

'**'

是字符串

这将与您的代码正常工作:

 procedure TForm1.Button1Click(Sender: TObject);
 Var
    C : Pchar;
    s : string;
 begin
    c:= PChar(string('*'));
    s := string(c); // AV here , but code works if i put C:= PChar('**') 
   ShowMessage(c);
end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接