var
str:string;
begin
str:='abc';
Memo1.Lines.Add('IntToHex(Integer(str),8) '+IntToHex(Integer(str),8));
Memo1.Lines.Add(IntToHex(Integer(@str[1]),8)+' '+IntToHex(Integer(str),8));//这句提前结果还可能不同
Memo1.Lines.Add('IntToHex(Integer(@str[1]),8) '+IntToHex(Integer(@str[1]),8))
end;
结果显示:
IntToHex(Integer(str),8) 00454664
004F3F08 004F3F08
IntToHex(Integer(@str[1]),8) 004F3F08
//上面显示的简直是个奇迹,第一次获取IntToHex(Integer(str),8)和第二次还可能不同,且不等于@str[1]
请教这到底是bug呢还是什么其他
integer(str)是str变量的指针地址。
我们首先声明一个变量
var
Str: String;此时integer(str)就有值了,Str的地址就确定了;而Str内容为空,@str[1]为0。然后Str := '123',此时@str[1]就不再为0了
Integer(@str[1])) 内存占用的地址,就是它指向的数据
或许我理解错了
但你说的没有初始化,我第一句就早已经str='abc'
首先我希望你能明白我的问题是什么,我对下面代码再次描述下
Memo1.Lines.Add('IntToHex(Integer(str),8) '+IntToHex(Integer(str),8));//代码1
Memo1.Lines.Add(IntToHex(Integer(@str[1]),8)+' '+IntToHex(Integer(str),8));//代码2
代码1中的结果和代码2中的结果在integer(str)这条指令上返回的不一致
如果你知道原因,请你解答下,谢谢!
integer(str)是str变量的指针地址。我们在声明了一个类型为string的变量str后,即var str: string;之后,integer(str)就能取到值了,这个值是str变量的地址。也就是不管这个变量现在的值是多少,即便为空值,integer(str)还是有值的,而且在应用程序运行期间都是不会变的。而此时如果str没有被赋值,那么@str[1]肯定就是0了。我们就来说说你已经赋值过的情况:
str := '123';之后,integer(str)还是开始声明str变量时候的值。但是它的内容(‘123’,指针所指向的内容)的地址随着str被赋值而开始改变了,@str[1]就不会等于0了,而是'123'字符串的首地址了。str ------> '123'
integer(str) 这个地址指针指向了'123'这个字符串的地址@str[1]。
所以integer(str)和@str[1]根本就是不同的概念
建议你google搜一下,当然可能现在得用baidu,bing之类的了var
str:string;
begin
str:='abc';这部分代码改成const
str:string='abc';
begin
//str:='abc';你会发现有意思的差别还是看一下copy-on-write的资料吧
呵呵,今天休息下,来学习回答问题.
str:='abc'; //这个时候 str 只是指向一个常量(字符串), 没有对 str 分配内存.
Memo1.Lines.Add('IntToHex(Integer(str),8) '+IntToHex(Integer(str),8)); //这种转换不会产生分配内存的问题
Memo1.Lines.Add(IntToHex(Integer(@str[1]),8)+' '+IntToHex(Integer(str),8)); // 这里 str[1] ,开始分内存了. 好了. 接下来你的问题就出现了.Memo1.Lines.Add('IntToHex(Integer(@str[1]),8) '+IntToHex(Integer(@str[1]),8))
不好意思,上面有些观点误导LZ了,看了华仔的解说,我更正一下:var
str: string;如果str未被赋值的话Integer(str)指向的也是0,我把字符串类型和其它类型数据搞混了。
但是一下观点目前个人认为还是正确的:
@str[1]是str内容的地址。
integer(str)是str变量的指针地址。
integer(str) 这个地址指针指向了'123'这个字符串的地址@str[1]。
所以integer(str)和@str[1]根本就是不同的概念
跟踪下汇编代码,你会发现 这个时候他执行了:sytem._UniqueString
@Str[1] , Integer(Str) 你的说法是对的.只是在:str:='abc'; 实质上 str 只是指向一个常量字符串的地址
我承认是我把问题想得太简单了,以至于没有看清楚LZ的问题描述,对不住LZ了。
谢谢华仔的解答,我也把这个问题给弄明白了!
这句话可以理解为2个步骤
1.创建堆内存<根据Delphi字符串的数据结构进行分配。常量的引用计数为-1>
2.在栈上创建一个存储单元
3.把创建堆内存时的首地址传给栈的储存单元中做存储单元的内容
所以就好理解了
Integer(Str)就是在栈上分配的存储单元的地址<记住,不是内容>
@Str[1]就是在堆内存是分配的地址
@与[]操作使得Delphi不清楚字串内容会否被修改,所以这时即使是读操作,也会激发copy-on-write,也就是sytem._UniqueString,这时,系统会发现
1 str是个变量,但它指向的是'abc'这个常量,
2 你作@,[]操作了,可能会修改str的内容,保持指向一个常量就不对了
这时系统会将abc复制一份,然后将str指向新的地方,而新的地方的引用计数是1如果你用
const
str:String='abc';来玩时,就会有另一番处理了,因为str本身就是常量,他的引用计数是-1,不会触发copy-on-write了
http://topic.csdn.net/u/20100513/17/86b3695f-d789-429f-96b7-3959c8189af2.html
比方说 'abc'的地址为 $00452158
则 Integer(Str) = $00452158, 在其他过程中也是能访问的
procedure T(Adress: DWORD);
asm
mov edx, eax
lea eax, [ebp-$04]
Call System.@LstrLAsg
mov eax, [ebp-$04]
Call showMessage
end;procedure TForm1.Button1Click(Sender: TObject);
var
Str: String;
begin
Str := 'abc';
end;procedure TForm1.Button2Click(Sender: TObject);
begin
T($00452158); // $00452158 只是测试时 'abc'常量在我程序里的位置,
end;