2017-05-18 2 views
0

Nous utilisons tous Delphi pour un projet depuis des années. Mais nous avons jamais vu la syntaxe suivante utilisée avec un PAnsiChar et ne savent pas ce que cela signifie:Que signifie ce code Delphi PAnsiChar?

buffer  : PAnsiChar 
recInstance : Byte 
recX   : smallint 
num_info  : integer 

// buffer loaded from a file... 

num_info := 0; 
// next two lines are a mystery 
recInstance := Byte(buffer[num_info*5]); 
recX := Byte(buffer[num_info*5+1])+256*Byte(buffer[num_info*5+2]); 

Dans le débogueur, il ressemble à recX chargement seulement 2 octets, mais la syntaxe ne semble pas correspondre.

Répondre

2

PAnsiChar a toujours eu la belle propriété que vous pouvez accéder au AnsiChar pointé du, ainsi que les AnsiChar s en utilisant la notation d'index suivants comme un tableau (d'octets ou AnsiChar s). C'est pourquoi il est utilisé ici.

Ces jours-ci, dans les versions modernes qui ont {$POINTERMATH}, vous préférez utiliser un PByte à la place, qui a la même indexation activée.

recInstance est affecté l'octet au décalage numinfo*5, recX est affecté les deux octets suivants comme une seule valeur de 16 bits.

Dans une version actuelle, il pourrait être écrit comme:

buffer: PByte; 
n: Integer; 

... 

n := num_info * 5; 
recInstance := buffer[n]; 
recX := buffer[n+1] or (buffer[n+2] shl 8); // together a 16 bit value 

Comme Remy a laissé entendre, vous pouvez lire les trois octets à la fois en utilisant:

type 
    PRec = ^TRec; 
    TRec = packed record 
    Instance: Byte; 
    X: Smallint; // a 16 bit (i.e. 2 byte) signed integer. 
    end; // total size: 3 bytes. 

var 
    MyRec: TRec; 

... 

    MyRec := PRec(@buffer[num_info * 5])^; 

Le PRec refondue -interprète l'adresse renvoyée par @buffer[num_info * 5] comme pointeur sur un TRec, puis déréférence (en utilisant ^) et affecte le résultat à MyRec.

En d'autres termes, @buffer[...] est un pointeur, PRec(...) tourne que dans un pointeur de type PRec et PRec(...)^ obtient les 3 octets à ce pointeur, comme si elle était un TRec.

MyRec.X est maintenant le même que recX et MyRec.Instance est maintenant le même que recInstance dans le code d'origine.

+0

J'utiliserais une distribution de type 'PSmallint' au lieu de concaténer les octets manuellement:' recX: = PSmallint (@buffer [n + 1]) ^; 'Ou mieux, définissez un enregistrement compressé et un transtypage de type à la place: 'type PRec =^TRec; TRec = reconditionné record d'enregistrement: Byte; recX: Smallint; fin; ... var buffer: PAnsiChar {ou PByte}; rec: TRec; ... rec: = PRec (@buffer [num_info * 5]) ^; ' –

+0

@Remy: Je pense à ça. Mais je pensais que cela ne clarifierait pas vraiment les choses, parce que la syntaxe 'PRec (@buffer [n]) ^' est encore plus difficile à comprendre pour quelqu'un qui a déjà du mal à comprendre l'utilisation de 'PAnsiChar' ici. Je voulais garder les choses aussi simples que possible. –

+0

Est-ce décalage 'num_info fois 5'? Étant donné que le type de données est un pointeur, l'astérisque est ce qui rejette tout le monde. – AlG

0

Byte() est de type juste coulée de la valeur de la taille d'un octet (AnsiChar ici) à l'octet de type

La dernière ligne de code forme variable à deux octets recX de deux octets (sans tenir compte des effets de débordement possibles si)

int16var = byte1 + 256 * byte2 
//almost equivalent of 
(byte2 shl 8) or byte1