我有方法(Delphi 2009):
procedure TAnsiStringType.SetData(const Value: TBuffer; IsNull: boolean = False); begin if not IsNull then FValue:= PAnsiString(Value)^; inherited; end;
这是基类上的抽象方法,其中"Value:Pointer"需要相应数据的指针,如下所示:
String = PString AnsiString = PAnsiString Integer = PInteger Boolean = PBoolean
所以我尝试传递这样的值:
var S: AnsiString; begin S:= 'New AnsiString Buffer'; SetBuffer(PAnsiString(S)); end;
但是从AnsiString到PAnsiString的转换不起作用,我可以看出原因,但我想知道转换的结果是什么.所以我写了一个简单的测试:
var Buffer: AnsiString; P1: Pointer; P2: Pointer; P3: Pointer; P4: Pointer; begin P1:= PAnsiString(Buffer); P2:= Addr(Buffer); P3:= @Buffer; P4:= Pointer(Buffer); P5:= PChar(Buffer[1]); WriteLn('P1: ' + IntToStr(Integer(P1))); WriteLn('P2: ' + IntToStr(Integer(P2))); WriteLn('P3: ' + IntToStr(Integer(P3))); WriteLn('P4: ' + IntToStr(Integer(P4))); WriteLn('P5: ' + IntToStr(Integer(P5))); end;
结果是:
P1: 5006500 P2: 1242488 P3: 1242488 P4: 5006500 P5: 67
哪里:
- P2 and P3, is the address of Buffer: AnsiString - P5 is the Char Ord value of Buffer[1] char, in this case "67 = C" - How about P1 and P4?
P1和P4是什么意思?
An AnsiString
实现为指针.一个AnsiString
变量保存不过是一个地址.地址是字符串中第一个字符的地址,或者nil
字符串是否为空.
A PAnsiString
是指向AnsiString
变量的指针.它是指向字符串第一个字符的指针.当你说PAnsiString(Buffer)
,你告诉编译器将指针Buffer
视为一个指针AnsiString
而不是指向字符数据的指针.地址5006500是字符串的第一个字符的位置C
.
您在内存中有一条代表字符串的记录:
+-----------+ | $ffffffff | -1 reference count (4 bytes) +-----------+ Buffer: | $00000001 | length (4 bytes) +---------+ +-----------+ | 5006500 | --> | 'C' | first character (1 byte) +---------+ +-----------+ | #0 | null terminator (1 byte) +-----------+
Buffer
保存字节的地址C
.你输入类型PAnsiString
而不是类型AnsiString
.你告诉编译器你有这个布局:
+-----------+ | ... | +-----------+ Buffer: | ... | +---------+ +-----------+ +-----------+ | 5006500 | --> | $00000043 | --> | garbage | first character +---------+ +-----------+ +-----------+ | ... | +-----------+
当我推理指针时,我就像这样绘制图表.如果你不在桌子旁边放一些纸,那你就是在伤害自己.
很好的谜题,但我有解决方案:
P2和P3是指向缓冲区的指针的地址
P1和P4是缓冲区的地址
P5是缓冲区中的第一个元素
我在代码中添加了注释:
var Buffer: AnsiString; P1: Pointer; P2: Pointer; P3: Pointer; P4: Pointer; P5: Pointer; begin P1:= PAnsiString(Buffer); (* A cast from AnsiString to PAnsiString has no real meaning because both are a pointer to a block of characters () P2:= Addr(Buffer); P3:= @Buffer; (* Both Addr and @ give the address of a variable. The variable Buffer is a pointer so we get the address of the pointer, not the value of the pointer. *) P4:= Pointer(Buffer); (* See the remark on P1. Due to the cast both give the same result. *) P5:= PChar(Buffer[1]); (* This looks like a pointer to the first element. But the cast changes it into the character. *) WriteLn('P1: ' + IntToStr(Integer(P1))); WriteLn('P2: ' + IntToStr(Integer(P2))); WriteLn('P3: ' + IntToStr(Integer(P3))); WriteLn('P4: ' + IntToStr(Integer(P4))); WriteLn('P5: ' + IntToStr(Integer(P5))); end;