5 votes

Que se passe-t-il lorsque AnsiString est transformé en PAnsiString ?

Je dispose de la méthode (Delphi 2009) :

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

Il s'agit d'une méthode abstraite de la classe de base, où "Value : Pointeur" attend le pointeur de la donnée correspondante, comme :

String = PString
AnsiString = PAnsiString
Integer = PInteger
Boolean = PBoolean

J'essaie donc de passer la valeur comme ceci :

var
  S: AnsiString;
begin
  S:= 'New AnsiString Buffer';
  SetBuffer(PAnsiString(S));
end;

Mais un casting de AnsiString vers PAnsiString ne fonctionne PAS, je peux voir pourquoi, mais je veux savoir quel est le résultat du casting. J'ai donc écrit un test simple :

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;

Le résultat est :

P1: 5006500
P2: 1242488
P3: 1242488
P4: 5006500
P5: 67

Où :

- 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?

Quelle est la signification de P1 et P4 ?

15voto

Rob Kennedy Points 107381

Un site AnsiString est implémenté comme un pointeur. Le site AnsiString ne contient rien d'autre qu'une adresse. L'adresse est celle du premier caractère de la chaîne, soit nil si la chaîne est vide.

A PAnsiString est un pointeur vers un AnsiString variable . C'est un pointeur sur un pointeur sur le premier caractère d'une chaîne de caractères. Lorsque vous dites PAnsiString(Buffer) vous demandez au compilateur de traiter le pointeur dans le fichier Buffer comme s'il s'agissait d'un pointeur vers un AnsiString au lieu d'un pointeur vers des données de caractère. L'adresse 5006500 est l'emplacement du premier caractère de la chaîne, C .

Vous avez en mémoire un enregistrement qui représente la chaîne de caractères :

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

Buffer contient l'adresse de l'octet avec C en elle. Tu fais un casting de type pour avoir le type PAnsiString au lieu de AnsiString . Vous avez dit au compilateur que vous aviez cette disposition :

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

Quand je raisonne sur les pointeurs, je dessine des diagrammes comme celui-ci. Si vous ne gardez pas du papier à côté de vous sur votre bureau, vous vous rendez un mauvais service.

7voto

Toon Krijthe Points 36327

Joli puzzle, mais j'ai la solution :

  • P2 et P3 sont les adresses du pointeur vers le tampon.
  • P1 et P4 sont les adresses du tampon.
  • P5 est le premier élément du tampon

J'ai ajouté un commentaire dans le 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;

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X