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呢还是什么其他

解决方案 »

  1.   

    @str[1]是str内容的地址。
    integer(str)是str变量的指针地址。
    我们首先声明一个变量
    var
      Str: String;此时integer(str)就有值了,Str的地址就确定了;而Str内容为空,@str[1]为0。然后Str := '123',此时@str[1]就不再为0了
      

  2.   

    integer(str) 存放变量的地址,都是在栈中
    Integer(@str[1])) 内存占用的地址,就是它指向的数据
      

  3.   

    如果我没理解错的话,你可以查一下字串的copy-on-write
    或许我理解错了
      

  4.   

    merrymin,首先我抱歉我的表达方式可能你有所紧张和误会,这可能是我对上面的问题很紧张的原因
    但你说的没有初始化,我第一句就早已经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)这条指令上返回的不一致
    如果你知道原因,请你解答下,谢谢!
      

  5.   

    没事,我上面可能也没跟你讲明白:@str[1]是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]根本就是不同的概念
      

  6.   

    关于这个,以前曾经有过相当不错的讨论,并且基本上得出了结论,但具体的网址我忘记了
    建议你google搜一下,当然可能现在得用baidu,bing之类的了var
      str:string;
    begin
      str:='abc';这部分代码改成const
      str:string='abc';
    begin
      //str:='abc';你会发现有意思的差别还是看一下copy-on-write的资料吧
      

  7.   


    呵呵,今天休息下,来学习回答问题.
      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))
      

  8.   

    终于有人知道我的疑惑在哪里了,谢谢,理解万岁!!!同时你说的有些道理,顺便问下,难道str[1]后会另外申请空间?
      

  9.   


    不好意思,上面有些观点误导LZ了,看了华仔的解说,我更正一下:var
      str: string;如果str未被赋值的话Integer(str)指向的也是0,我把字符串类型和其它类型数据搞混了。
    但是一下观点目前个人认为还是正确的:
    @str[1]是str内容的地址。
    integer(str)是str变量的指针地址。
    integer(str) 这个地址指针指向了'123'这个字符串的地址@str[1]。
    所以integer(str)和@str[1]根本就是不同的概念
      

  10.   


    跟踪下汇编代码,你会发现 这个时候他执行了:sytem._UniqueString 
      

  11.   


    @Str[1] , Integer(Str) 你的说法是对的.只是在:str:='abc';  实质上 str 只是指向一个常量字符串的地址
      

  12.   


    我承认是我把问题想得太简单了,以至于没有看清楚LZ的问题描述,对不住LZ了。
    谢谢华仔的解答,我也把这个问题给弄明白了!
      

  13.   

    str='abc'
    这句话可以理解为2个步骤
    1.创建堆内存<根据Delphi字符串的数据结构进行分配。常量的引用计数为-1>
    2.在栈上创建一个存储单元
    3.把创建堆内存时的首地址传给栈的储存单元中做存储单元的内容
    所以就好理解了
    Integer(Str)就是在栈上分配的存储单元的地址<记住,不是内容>
    @Str[1]就是在堆内存是分配的地址
      

  14.   

    实际上我个人认为是
    @与[]操作使得Delphi不清楚字串内容会否被修改,所以这时即使是读操作,也会激发copy-on-write,也就是sytem._UniqueString,这时,系统会发现
    1 str是个变量,但它指向的是'abc'这个常量,
    2 你作@,[]操作了,可能会修改str的内容,保持指向一个常量就不对了
    这时系统会将abc复制一份,然后将str指向新的地方,而新的地方的引用计数是1如果你用
    const
      str:String='abc';来玩时,就会有另一番处理了,因为str本身就是常量,他的引用计数是-1,不会触发copy-on-write了
      

  15.   

    顺个大便,帮忙看一下我的问题
    http://topic.csdn.net/u/20100513/17/86b3695f-d789-429f-96b7-3959c8189af2.html
      

  16.   

    Integer(Str)就是在栈上分配的存储单元的地址<记住,不是内容>不太同意博士的,str := 'abc', 'abc' 属于文字常量区, 不是栈,常量字符串放在文字常量区,程序结束后由系统释放
    比方说 '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;