What happens when AnsiString is cast to PAnsiString?

后端 未结 2 516
花落未央
花落未央 2021-02-10 10:56

I have the method (Delphi 2009):

procedure TAnsiStringType.SetData(const Value: TBuffer; IsNull: boolean = False);
begin
  if not IsNull then
    FValue:= PAnsiS         


        
相关标签:
2条回答
  • 2021-02-10 11:29

    Nice puzzle, but I have the solution:

    • P2 and P3 are the address of the pointer to the buffer
    • P1 and P4 are the address of the buffer
    • P5 is the first element in the buffer

    I have added comment in the code:

    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;
    
    0 讨论(0)
  • 2021-02-10 11:34

    An AnsiString is implemented as a pointer. An AnsiString variable holds nothing but an address. The address is that of the first character in the string, or nil if the string is empty.

    A PAnsiString is a pointer to an AnsiString variable. It's a pointer to a pointer to the first character of a string. When you say PAnsiString(Buffer), you're telling the compiler to treat the pointer in Buffer as though it were a pointer to an AnsiString instead of a pointer to character data. The address 5006500 is the location of the first character of the string, C.

    You have a record in memory that represents the string:

                    +-----------+
                    | $ffffffff | -1 reference count (4 bytes)
                    +-----------+
    Buffer:         | $00000001 | length (4 bytes)
    +---------+     +-----------+
    | 5006500 | --> |       'C' | first character (1 byte)
    +---------+     +-----------+
                    |        #0 | null terminator (1 byte)
                    +-----------+
    

    Buffer holds the address of the byte with C in it. You type-cast that to have type PAnsiString instead of AnsiString. You told the compiler that you had this layout:

                                      +-----------+
                                      |       ... |
                                      +-----------+
    Buffer:                           |       ... |
    +---------+     +-----------+     +-----------+
    | 5006500 | --> | $00000043 | --> |   garbage | first character
    +---------+     +-----------+     +-----------+
                                      |       ... |
                                      +-----------+
    

    When I'm reasoning about pointers, I draw diagrams just like this. If you don't keep some paper next to you on your desk, you're doing yourself a disservice.

    0 讨论(0)
提交回复
热议问题