先来段代码
type
MyString = AnsiString;
PMyChar = PAnsiChar;
procedure TForm2.Button2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest '; // 7位的字符串
p := GetCaption;
s2 := p; //这是时候s2 为frmTes
ShowMessage(s2); //*****显示出来为frmTes
end;
function TForm2.GetCaption: PMyChar;
var
s1, s2: MyString;
begin
s2 := MyString(self.Caption);
Result := PMyChar(MyString(s2));
end;
MyString = AnsiString;
PMyChar = PAnsiChar;
procedure TForm2.Button2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest '; // 7位的字符串
p := GetCaption;
s2 := p; //这是时候s2 为frmTes
ShowMessage(s2); //*****显示出来为frmTes
end;
function TForm2.GetCaption: PMyChar;
var
s1, s2: MyString;
begin
s2 := MyString(self.Caption);
Result := PMyChar(MyString(s2));
end;
研究说明(代表个人意见)(XE下面测试)
function TForm2.GetCaption: PMyChar;
var
s1: MyString;
begin
s1 := MyString(Self.Caption); //self.Caption源码得知,是获取了一块临时的空间(A1)
//A1(integer(s1))
i:= StringRefCount(s1); //i= 1
Result := PMyChar(MyString(s1)); //Result指针指向的为(A1)的空间
//Integer(@Result^) = A1(integer(s1)) 是指向同一块空间
i:= StringRefCount(s1); //i= 1
end;
//函数返回后s1因为是局部变量 s1的引用计数为0,integer(s1)的空间被标志为可以覆盖
//返回的为指针,不增加s1的引用计数
procedure TForm2.Button2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest ';
p := GetCaption; //实际上p指向的那块地址被标注为可以覆盖,随时都有可能被覆盖,是很危险的
//Integer(@p^) = GetCaption内部给s1分配的那块空间地址
var
s1: MyString;
begin
s1 := MyString(Self.Caption); //self.Caption源码得知,是获取了一块临时的空间(A1)
//A1(integer(s1))
i:= StringRefCount(s1); //i= 1
Result := PMyChar(MyString(s1)); //Result指针指向的为(A1)的空间
//Integer(@Result^) = A1(integer(s1)) 是指向同一块空间
i:= StringRefCount(s1); //i= 1
end;
//函数返回后s1因为是局部变量 s1的引用计数为0,integer(s1)的空间被标志为可以覆盖
//返回的为指针,不增加s1的引用计数
procedure TForm2.Button2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest ';
p := GetCaption; //实际上p指向的那块地址被标注为可以覆盖,随时都有可能被覆盖,是很危险的
//Integer(@p^) = GetCaption内部给s1分配的那块空间地址
s2 := p; //导致丢掉了字符..
//因为p指向的内存是可以被覆盖的,s2分配的地址可能和p指向的地址是一样的,导致丢掉了字符..
//Integer(s2) 可能= Integer(@p^) 测试是发现都一样
//下面操作(SetLength)同样也会一样结果,s2占用的和p占用的同样大小(或者小)。
//这样导致了s2分配的空间可能和p内存一样
//如果7改成较大的数就正常
// SetLength(s2, 7);
// StrCopy(PMyChar(s2), p);
//因为p指向的内存是可以被覆盖的,s2分配的地址可能和p指向的地址是一样的,导致丢掉了字符..
//Integer(s2) 可能= Integer(@p^) 测试是发现都一样
//下面操作(SetLength)同样也会一样结果,s2占用的和p占用的同样大小(或者小)。
//这样导致了s2分配的空间可能和p内存一样
//如果7改成较大的数就正常
// SetLength(s2, 7);
// StrCopy(PMyChar(s2), p);
ShowMessage(s2); //错误
end;
解决方案(1)
将s1定义为内成员变量,这样当GetCaption执行完后那块空间不会被标准为可读写
function TForm2.GetCaption2: PMyChar;
begin
FMyCaption := MyString(Self.Caption); //self.Caption源码得知,是获取了一块临时的空间(A1)
//A1(integer(FMyCaption))
i:= StringRefCount(FMyCaption); //i= 1
Result := PMyChar(MyString(FMyCaption)); //Result指针指向的为(A1)的空间
//Integer(@Result^) = A1(integer(FMyCaption)) 是指向同一块空间
i:= StringRefCount(FMyCaption); //i= 1
end;
//执行完后FMyCaption不是临时变量,指向的地址不可以被覆盖
procedure TForm2.btnGetCaption2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest ';
p := GetCaption2; //实际上p指向的那块地址和FMyCaption的地址是一样的
//Integer(@p^) = GetCaption2内部给FMyCaption分配的那块空间地址是一样
begin
FMyCaption := MyString(Self.Caption); //self.Caption源码得知,是获取了一块临时的空间(A1)
//A1(integer(FMyCaption))
i:= StringRefCount(FMyCaption); //i= 1
Result := PMyChar(MyString(FMyCaption)); //Result指针指向的为(A1)的空间
//Integer(@Result^) = A1(integer(FMyCaption)) 是指向同一块空间
i:= StringRefCount(FMyCaption); //i= 1
end;
//执行完后FMyCaption不是临时变量,指向的地址不可以被覆盖
procedure TForm2.btnGetCaption2Click(Sender: TObject);
var
p: PMyChar;
s, s2: MyString;
begin
self.Caption := ' frmTest ';
p := GetCaption2; //实际上p指向的那块地址和FMyCaption的地址是一样的
//Integer(@p^) = GetCaption2内部给FMyCaption分配的那块空间地址是一样
s2 := p;
//因为p指向的内存是不可以被覆盖的,s2分配的地址不可可能和p指向的地址是一样的,这样做是安全的
//Integer(s2) <> Integer(@p^)
i:= StringRefCount(s2); //i= 1 新的内存
ShowMessage(s2); //正确
end;
***
局部变量
function TForm2.GetCaption2: PMyChar;
var
s1: MyString;
begin
var
s1: MyString;
begin
s1 :=
'
frmTest
'
i:= StringRefCount(s1); //i=- 1 常量地址指向空间不可被覆盖
i:= StringRefCount(s1); //i=- 1 常量地址指向空间不可被覆盖
//UniqueString(s1);
//i:= StringRefCount(s1); //i= 1 s1又变成临时的,函数返回后s1指向的地址不再安全
//i:= StringRefCount(s1); //i= 1 s1又变成临时的,函数返回后s1指向的地址不再安全
Result=PMyChar(s1)
end;
end;