Afficher : Delphi C++
Préférences d'affichage

Formats de données internes (Delphi)

De RAD Studio

Sommaire


Les rubriques suivantes décrivent les formats internes des types de données Delphi.

Types entiers

Les valeurs entières ont la représentation interne suivante dans Delphi.

Types entiers non signés indépendants de la plate-forme

Les valeurs des types entiers indépendants de la plate-forme occupent le même nombre de bits sur toutes les plates-formes.

Les valeurs des types entiers non signés sont toujours positives et n'impliquent pas un bit de signe comme le font les types entiers signés. Tous les bits des types entiers non signés sont occupés par la magnitude de la valeur et n'ont aucune autre signification.


Byte, UInt8

Byte et UInt8 sont des nombres entiers positifs non signés sur 1 octet (8 bits). La magnitude occupe la totalité des 8 bits.

Entier non signé sur 8 bits


Word et UInt16

Word et UInt16 sont des nombres entiers non signés sur 2 octets (16 bits).

Entier non signé sur 16 bits


Cardinal, LongWord et UInt32

Cardinal, LongWord et UInt32 sont des nombres entiers non signés sur 4 octets (32 bits).

Entier non signé sur 32 bits


UInt64

UInt64 sont des nombres entiers non signés sur 8 octets (64 bits).

Entier non signé sur 64 bits


Types entiers signés indépendants de la plate-forme

Les valeurs des types entiers signés n'ont pas besoin de représenter le signe d'un nombre par un bit de signe de tête, exprimé par le bit le plus significatif. Le signe de bit est 0 pour un nombre positif, et 1 pour un nombre négatif. Les autres bits d'un nombre entier signé positif sont occupés par la magnitude. Dans un nombre entier signé négatif, les autres bits sont occupés par la représentation en complément à 2 de la magnitude de la valeur (valeur absolue).

Pour transformer le complément à 2 en une magnitude :

  1. En partant de la droite, trouvez le premier '1'.
  2. Inversez tous les bits situés sur la gauche de celui-ci.

Par exemple :

Exemple 1 Exemple 2
Magnitude 0101010 1010101

Complément à 2

1010110 01010110


ShortInt, Int8

Shortint et Int8 sont des nombres entiers signés sur 1 octet (8 bits). Le bit de signe occupe le bit 7 le plus significatif, la magnitude ou le complément à 2 occupe les autres 7 bits.

Entier signé positif sur 8 bits
Entier signé négatif sur 8 bits


SmallInt et Int16

SmallInt et Int16 sont des nombres entiers signés sur 2 octets (16 bits).

Entier signé positif sur 16 bits
Entier signé négatif sur 16 bits


Integer, LongInt et Int32

Integer, LongInt et Int32 sont des nombres entiers signés sur 4 octets (32 bits).

Entier signé positif sur 32 bits
Entier signé négatif sur 32 bits


Int64

Int64 sont des nombres entiers signés sur 8 octets (64 bits).

Entier signé positif sur 64 bits
Entier signé négatif sur 64 bits


Types entiers dépendants de la plate-forme

Les types entiers dépendants de la plate-forme sont NativeUInt et NativeInt. Les types entiers dépendants de la plate-forme sont transformés pour s'ajuster à la taille en bits de la plate-forme cible en cours. Sur les plates-formes 64 bits, ils occupent 64 bits, sur les plates-formes 32 bits, ils occupent 32 bits. Quand la taille de la plate-forme cible est la même que la plate-forme CPU, un nombre entier dépendant de la plate-forme correspond alors exactement à la taille des registres CPU. Ces types sont souvent utilisés quand de meilleures performances sont souhaitées pour un type de CPU et système d'exploitation particuliers.

Entier non signé NativeUInt

NativeUInt est le type entier non signé dépendant de la plate-forme. La taille et la représentation interne de NativeUInt dépend de la plate-forme en cours. Sur les plates-formes 32 bits, NativeUInt est équivalent au type Cardinal. Sur les plates-formes 64 bits, NativeUInt est équivalent au type UInt64.


Entier signé NativeInt

NativeInt est le type entier signé dépendant de la plate-forme. La taille et la représentation interne de NativeInt dépend de la plate-forme en cours. Sur les plates-formes 32 bits, NativeInt est équivalent au type Integer. Sur les plates-formes 64 bits, NativeInt est équivalent au type Int64.

Types sous-intervalle entiers

Quand vous utilisez des constantes entières pour définir les bornes inférieure et supérieure d'un type sous-intervalle, vous définissez un type sous-intervalle entier. Un type sous-intervalle entier représente un sous-ensemble des valeurs d'un type entier (appelé le type de base). Le type de base est le type entier le plus petit qui contient l'intervalle spécifié (contient à la fois les bornes inférieure et supérieure).

Le format de données interne d'une variable de type sous-intervalle entier dépend de ses bornes inférieure et supérieure :

  • Si les deux bornes sont contenues dans l'intervalle -128..127 (Shortint), la variable est stockée sous la forme d'un octet signé.
  • Si les deux bornes sont contenues dans l'intervalle 0..255 (Byte), la variable est stockée sous la forme d'un octet non signé.
  • Si les deux bornes sont contenues dans l'intervalle -32768..32767 (Smallint), la variable est stockée sous la forme d'un mot signé.
  • Si les deux bornes sont contenues dans l'intervalle 0..65535 (Word), la variable est stockée sous la forme d'un mot non signé.
  • Si les deux bornes sont contenues dans l'intervalle -2147483648..2147483647 (Longint), la variable est stockée sous la forme d'un double mot signé.
  • Si les deux bornes sont contenues dans l'intervalle 0..4294967295 (Longword), la variable est stockée sous la forme d'un double mot non signé.
  • Sinon, la variable est stockée sous la forme d'un quadruple mot signé (Int64).
Remarque : Un "mot" occupe deux octets.

Types caractères

Sur la plate-forme Win32 :

  • Char et WideChar sont stockés sous la forme d'une variable d'un mot non signé, en utilisant normalement l'encodage UTF-16 ou Unicode.
  • AnsiChar et les rangées d'un type Char sont stockés sous la forme d'un octet non signé. Dans Delphi 2007 et les versions antérieures, Char était représenté sous la forme d'un AnsiChar. Le type de caractère utilisé avec les chaînes courtes est toujours AnsiChar et il est stocké dans des valeurs d'octets non signés.
  • Le type de chaîne longue par défaut (string) est à présent UnicodeString, avec compteur de références similaire à AnsiString, l'ancien type de chaîne longue par défaut. La compatibilité avec l'ancien code peut nécessiter l'usage du type AnsiString.
  • WideString est composé de WideChars comme UnicodeString, mais n'utilise pas le comptage des références.

Types booléens

Un type Boolean est stocké sous la forme d'un Byte, un type ByteBool est stocké sous la forme d'un Byte, un type WordBool est stocké sous la forme d'un Word et un LongBool est stocké sous la forme d'un Longint.

Un Boolean peut prendre les valeurs 0 (False) et 1 (True). Les types ByteBool, WordBool et LongBool acceptent les valeurs nulles (False) et non nulles (True).

Types énumérés

Un type énuméré est stocké sous la forme d'un octet non signé si l'énumération ne comporte pas plus de 256 valeurs et si le type a été déclaré dans l'état {$Z1} (ce qui est le cas par défaut). Si un type énuméré a plus de 256 valeurs ou si le type a été déclaré en mode {$Z2}, il est stocké sous la forme d'un mot non signé. Si un type énuméré est déclaré dans l'état {$Z4}, il est stocké sous la forme d'un mot double non signé.

Types réels

Les types réels stockent la représentation binaire d'un signe, (+ ou -), d'un exposant et d'une mantisse (significand). Une valeur réelle a la forme :

+/- significand * 2^exponent

significand ne possède qu'un bit à gauche de la virgule décimale binaire (c'est-à-dire, 0 <= significand < 2).

Dans les images suivantes, le bit le plus significatif est toujours à gauche et le bit le moins significatif à droite. Les nombres en haut indiquent la largeur (exprimée en bits) de chaque champ, les éléments les plus à gauche étant stockés aux adresses les plus élevées. Par exemple, pour une valeur Real48, e est stocké dans le premier octet, f dans les cinq octets suivants et s dans le bit le plus significatif du dernier octet.

Le type Real48

Sur les plates-formes Win32, un nombre Real48 sur 6 octets (48 bits) est divisé en trois champs.

1

           39                               

     8     

s

          f

    e


Si 0 < e <= 255, la valeur v du nombre est donnée par :

v = (-1)s * 2(e-129) * (1.f)

Si e = 0, alors v = 0.

Le type Real48 ne peut pas stocker des nombres dénormalisés, NaN ou infinis. Les nombres dénormalisés deviennent nuls quand ils sont stockés dans un Real48, et les nombres NaN et infinis produisent une erreur de dépassement de capacité lorsqu'on tente de les stocker dans un Real48.

Le type Single

Un nombre Single sur 4 octets (32 bits) est divisé en trois champs.

1

     8     

           23           

s

    e

          f


La valeur v du nombre est donnée par :

  • Si 0 < e < 255, alors v = (-1)s * 2(e-127) * (1.f)
  • Si e = 0 et f <> 0, alors v = (-1)s * 2(-126) * (0.f)
  • Si e = 0 et f = 0, alors v = (-1)s * 0
  • Si e = 255 et f = 0, alors v = (-1)s * Inf
  • Si e = 255 et f <> 0, alors v est un NaN

Le type Double

Dans l'implémentation en cours, le type Real est équivalent à Double.

Un nombre Double sur 8 octets (64 bits) est divisé en trois champs.

1

      11      

                          52                          

s

     e

                         f


La valeur v du nombre est donnée par :

  • Si 0 < e < 2047, alors v = (-1)s * 2(e-1023) * (1.f)
  • Si e = 0 et f <> 0, alors v = (-1)s * 2(-1022) * (0.f)
  • Si e = 0 et f = 0, alors v = (-1)s * 0
  • Si e = 2047 et f = 0, alors v = (-1)s * Inf
  • Si e = 2047 et f <> 0, alors v est un NaN

Le type Extended

Sur les plates-formes 64 bits, le type Extended est un alias pour Double, qui est seulement de 8 octets. Voir la section Le type Double ci-dessus. Pour de plus amples informations, voir Considérations Delphi pour les applications multiplates-formes.

Sur les plates-formes 32 bits, un nombre Extended est représenté sur 10 octets (80 bits). Un nombre Extended est divisé en quatre champs.

1

         15         

1

                                 63                                 

s

        e

i

                                f


La valeur v du nombre est donnée par :

  • Si 0 <= e < 32767, alors v = (-1)s * 2(e-16383) * (i.f)
  • Si e = 32767 et f = 0, alors v = (-1)s * Inf
  • Si e = 32767 et f <> 0, alors v est un NaN

Le type Comp

Un nombre Comp sur 8 octets (64 bits) est stocké comme un entier signé sur 64 bits.

Le type Currency

Un nombre Currency sur 8 octets (64 bits) est stocké sous la forme d'un entier scalaire et signé sur 64 bits, dont les 4 chiffres les moins significatifs représentent implicitement 4 positions décimales.

Types pointeur

Sur les plates-formes 32 bits, un type pointeur est stocké dans 4 octets sous une adresse 32 bits. Sur les plates-formes 64 bits, un type pointeur est stocké dans 8 octets sous une adresse 64 bits.

La valeur pointeur nil est stockée sous la forme zéro.

Types chaînes courtes

Une chaîne occupe le nombre d'octets correspondant à sa longueur maximale plus un. Le premier octet contient la longueur dynamique réelle de la chaîne et les octets suivants contiennent ses caractères.

L'octet de longueur et les caractères sont des valeurs non signées. La longueur de chaîne maximale est de 255 caractères plus un octet de longueur (string[255]).

Types chaînes longues

Une variable chaîne de type UnicodeString ou AnsiString occupe 4 octets de mémoire, qui contiennent un pointeur sur une chaîne allouée dynamiquement. Quand une variable chaîne est vide (contient une chaîne d'une longueur de zéro), le pointeur chaîne est nil et aucune mémoire dynamique n'est associée avec la variable chaîne. Pour une valeur de chaîne non vide, le pointeur chaîne pointe sur un bloc de mémoire alloué dynamiquement qui contient la valeur de la chaîne en plus des informations décrivant la chaîne. Le tableau suivant montre le contenu d'un bloc mémoire de chaîne longue.

Disposition mémoire dynamique d'une chaîne (Win32 seulement)

Décalage Contenu

-12

Page de code 16 bits de données chaîne

-10

Taille d'élément 16 bits de données chaîne

-8

Compteur de références sur 32 bits

-4

Longueur en octets

0..Longueur - 1

Chaîne de caractères de données dimensionnées en éléments

Longueur*Taille d'élément

Caractère NULL


Le caractère NULL à la fin d'un bloc mémoire de chaîne est automatiquement géré par le compilateur et les routines de gestion de chaîne intégrées. Cela rend possible le transtypage direct d'une chaîne par une chaîne à zéro terminal.

Pour les littéraux chaîne, le compilateur génère un bloc mémoire de même disposition qu'une chaîne allouée dynamiquement mais avec un compte de références de -1. Les constantes chaîne sont traitées de la même façon, la seule différence étant que les littéraux sont un pointeur sur un bloc de compteur de références de -1.

Quand un pointeur sur une structure chaîne (source) est assigné à une variable chaîne (destination), le compteur de références dicte la façon de faire. Généralement, le compte de références est diminué pour la destination et augmenté pour la source parce que les deux pointeurs, source et destination, pointeront sur le même bloc de mémoire après l'affectation.

Si le compte de références source est -1 (constante chaîne), une nouvelle structure est créée avec un compte de références de 1. Si la destination ne vaut pas nil, le compteur de références est diminué. S'il atteint 0, la structure est désallouée de la mémoire. Si la destination vaut nil, aucune action supplémentaire n'est entreprise. La destination pointera alors sur la nouvelle structure.

 var
 destination : String;
 source : String;
...
destination := 'qwerty';  // reference count for the newly-created block of memory (containing the 'qwerty' string) pointed at by the "destination" variable is now 1
...
source := 'asdfgh'; // reference count for the newly-created block of memory (containing the 'asdfgh' string) pointed at by the "destination" variable is now 1
destination := source; // reference count for the memory block containing the 'asdfgh' string is now 2, and since reference count for the block of memory containing the 'qwerty' string is now 0, the memory block is deallocated.

Si le compte de références source n'est pas -1, il est incrémenté et la destination pointera sur lui.

 var
   destination, destination2, destination3: String;
  destination := 'Sample String'; //reference count for the newly-created block of memory containing 'Sample string' is 1.
  destination2 := destination; //reference count for the block of memory containing 'Sample string' is now 2.
  destination3 := destination; //reference count for the block of memory containing 'Sample string' is now 3.
Remarque : Aucune variable chaîne ne peut pointer sur une structure avec un compte de références de 0. Les structures sont toujours désallouées lorsqu'elles atteignent un compte de références de 0 et ne peuvent pas être modifiées lorsqu'elles ont un compte de références de -1.

Types chaînes étendues

Sur Win32, une variable chaîne étendue occupe 4 octets de mémoire qui contiennent un pointeur sur une chaîne allouée dynamiquement. Lorsqu'une variable chaîne étendue est vide (contient une chaîne d'une longueur de zéro), le pointeur de chaîne est nil et aucune mémoire dynamique n'est associée avec la variable chaîne. Pour une valeur de chaîne non vide, le pointeur de chaîne pointe un bloc de mémoire alloué dynamiquement qui contient la valeur de la chaîne en plus d'un indicateur de longueur 32 bits. Le tableau suivant montre le contenu d'un bloc mémoire de chaîne étendue sur Windows.

Disposition en mémoire dynamique d'une chaîne étendue (Win32 seulement)

Offset Contenu

-4

Indicateur de longueur sur 32 bits (en octets)

0..Longueur -1

Chaîne de caractères

Longueur

Caractère NULL


La longueur de la chaîne est évaluée en octets, c'est donc le double du nombre de caractères contenus dans la chaîne.

Le caractère NULL à la fin d'un bloc mémoire de chaîne étendue est automatiquement géré par le compilateur et les routines de gestion de chaîne intégrées. Cela rend possible le transtypage direct d'une chaîne étendue par une chaîne à zéro terminal.

Types ensemble

Un ensemble est un tableau de bits dans lequel chaque bit indique si un élément est présent dans l'ensemble ou non. Le nombre maximal d'éléments dans un ensemble est 256, et un ensemble n'occupe donc jamais plus de 32 octets. Le nombre d'octets occupés par un ensemble particulier est calculé comme suit :

(Max div 8) - (Min div 8) + 1

Max et Min sont les bornes inférieure et supérieure du type de base de l'ensemble. Le numéro de l'octet d'un élément particulier E est :

(E div 8) - (Min div 8)

Et le numéro du bit à l'intérieur de cet octet est :

E mod 8

E désigne la valeur ordinale de l'élément. Quand c'est possible, le compilateur stocke les ensembles dans les registres CPU, mais un ensemble réside toujours en mémoire s'il est plus grand que le type entier générique ou si le programme contient du code qui utilise l'adresse de l'ensemble.

Types tableaux statiques

Sur la plate-forme Win32, un tableau statique est stocké sous la forme d'une suite contiguë de variables du type de composant du tableau. Les éléments d'index les plus faibles sont stockés aux adresses mémoire les plus faibles. Dans un tableau multidimensionnel, la dimension la plus à droite est celle qui s'incrémente en premier.

Types tableaux dynamiques

Sur la plate-forme Win32, une variable tableau dynamique occupe 4 octets de mémoire qui contiennent un pointeur sur le tableau alloué dynamiquement. Quand la variable est vide (non initialisée) ou contient un tableau de longueur nulle, le pointeur vaut nil et il n'y a pas de mémoire dynamique associée à la variable. Pour un tableau non vide, la variable pointe sur un bloc de mémoire alloué dynamiquement qui contient en plus du tableau un indicateur de longueur sur 32 bits et un compteur de références sur 32 bits. Le tableau suivant indique l'organisation du bloc de mémoire de tableau alloué dynamiquement.

Disposition en mémoire d'un tableau dynamique (Win32 seulement)

Offset Contenu

-8

Compteur de références sur 32 bits

-4

Indicateur de longueur sur 32 bits (nombre d'éléments)

0..Longueur * (taille d'élément) -1

Eléments du tableau

Types enregistrements

Quand un type enregistrement est déclaré dans l'état {$A+} (valeur par défaut) et que la déclaration ne comprend pas de modificateur packed, le type est unpacked record, et les champs de l'enregistrement sont alignés pour faciliter l'accès par la CPU, et conformément à la plate-forme. L'alignement est contrôlé par le type de chaque champ. Chaque type de données a un alignement inhérent, automatiquement calculé par le compilateur. L'alignement peut être 1, 2, 4 ou 8 et représente la limite en octets sur laquelle une valeur du type doit être stockée pour que l'accès soit plus efficace. Le tableau suivant liste les alignements pour tous les types de données.

Masques d'alignement des types (Win32 seulement)

Type Alignement

Types ordinaux

Taille du type (1, 2, 4 ou 8)

Types réels

2 pour Real48, 4 pour Single, 8 pour Double et Extended

Types chaînes courtes

1

Types tableaux

Identique au type des éléments du tableau

Types enregistrements

Le plus grand alignement des champs de l'enregistrement

Types ensembles

Taille du type si 1, 2 ou 4, sinon 1

Tous les autres types

Déterminé par la directive $A


Pour que l'alignement des champs soit correct dans un type enregistrement décompacté, le compilateur insère un octet inutilisé avant les champs ayant un alignement de 2, et jusqu'à 3 octets inutilisés avant les champs ayant un alignement de 4, si nécessaire. Enfin, le compilateur arrondit la taille totale de l'enregistrement jusqu'à la limite en octets spécifiée par l'alignement le plus grand des champs.

Alignement packed implicite des champs avec une spécification de type commune

Les versions antérieures du compilateur Delphi, telles que Delphi 7 et avant, appliquaient implicitement l'alignement packed aux champs qui étaient déclarés ensemble, c'est-à-dire les champs ayant une spécification de type commune. Les compilateurs plus récents peuvent reproduire ce comportement si vous spécifiez la directive {$OLDTYPELAYOUT ON}. Cette directive aligne sur les octets (alignement packed) les champs ayant une spécification de type commune, même si la déclaration n'inclut pas le modificateur packed et si le type enregistrement n'est pas déclaré dans l'état {$A-}.

Ainsi, par exemple, soit la déclaration suivante :

 {$OLDTYPELAYOUT ON}
  type
    TMyRecord = record
      A, B: Extended;
      C: Extended;
    end;
  {$OLDTYPELAYOUT OFF}

A et B sont alignés sur des limites en octets (alignement packed) car la directive {$OLDTYPELAYOUT ON} est spécifiée et que A et B partagent la même spécification de type. Toutefois, pour le champ C déclaré séparément, le compilateur utilise le comportement par défaut et complète la structure avec des octets inutilisés pour garantir que le champ apparaît sur une limite de mot quadruple.

Quand un type enregistrement est déclaré dans l'état {$A-} ou que la déclaration inclut le modificateur packed, les champs de l'enregistrement ne sont pas alignés, mais des décalages consécutifs leur sont plutôt assignés. La taille totale d'un tel enregistrement packed est simplement la taille de tous les champs. Puisque l'alignement des données peut changer, c'est une bonne idée de compacter toute structure d'enregistrement que vous avez l'intention d'écrire sur disque ou de passer en mémoire à un autre module compilé avec une version du compilateur différente.

Types de fichiers

Sur les plates-formes Win32, les types de fichiers sont représentés sous forme d'enregistrements. Les fichiers typés et non typés occupent 592 octets, disposés comme suit :

 type
    TFileRec = packed record
      Handle: Integer;
      Mode: word;
      Flags: word;
      case Byte of
        0: (RecSize: Cardinal);
        1: (BufSize: Cardinal;
     	   BufPos: Cardinal;
     	   BufEnd: Cardinal;
     	   BufPtr: PChar;
     	   OpenFunc: Pointer;
     	   InOutFunc: Pointer;
     	   FlushFunc: Pointer;
     	   CloseFunc: Pointer;
     	   UserData: array[1..32] of Byte;
     	   Name: array[0..259] of Char; );
   end;

Les fichiers texte occupent 848 octets, disposés comme suit :

 type
    TTextBuf = array[0..127] of Char;
    TTextRec = packed record
      Handle: Integer;
      Mode: word;
      Flags: word;
      BufSize: Cardinal;
      BufPos: Cardinal;
      BufEnd: Cardinal;
      BufPtr: PChar;
      OpenFunc: Pointer;
      InOutFunc: Pointer;
      FlushFunc: Pointer;
      CloseFunc: Pointer;
      UserData: array[1..32] of Byte;
      Name: array[0..259] of Char;
      Buffer: TTextBuf;
   end;

Handle contient le handle du fichier (quand le fichier est ouvert).

Le champ Mode peut prendre l'une des valeurs suivantes :

 const
    fmClosed = $D7B0;
    fmInput= $D7B1;
    fmOutput = $D7B2;
    fmInOut= $D7B3;

fmClosed indique que le fichier est fermé. fmInput et fmOutput indiquent un fichier texte qui a été réinitialisé (fmInput) ou réécrit (fmOutput), fmInOut indique un fichier typé ou non typé qui a été réinitialisé ou réécrit. Toute autre valeur indique que la variable fichier n'a pas été affectée (et qu'elle n'est donc pas initialisée).

Le champ UserData est disponible pour les routines écrites par l'utilisateur afin d'y stocker des données.

Name contient le nom du fichier, qui est une séquence de caractères terminée par un caractère null (#0).

Pour les fichiers typés et les fichiers non typés, RecSize contient la longueur de l'enregistrement en octets, et le champ Private est inutilisé mais réservé.

Pour les fichiers texte, BufPtr est un pointeur sur un tampon de BufSize octets, BufPos est l'index dans le tampon du prochain caractère à lire à ou écrire, et BufEnd représente le nombre de caractères valides dans le tampon. OpenFunc, InOutFunc, FlushFunc et CloseFunc sont des pointeurs sur les routines d'E/S qui contrôlent le fichier ; voir Fonctions de périphérique. Flags détermine le style de saut de ligne comme suit.

bit 0 vide

Sauts de ligne LF

bit 0 défini

Sauts de ligne CRLF

Tous les autres bits Flags sont réservés pour un usage ultérieur.

Remarque : Pour l'utilisation du type UnicodeString (le type de chaîne Delphi par défaut), les divers types de flux de l'unité Classes (TFileStream, TStreamReader, TStreamWriter, et ainsi de suite) sont plus utiles, puisque les anciens types de fichiers ont une fonctionnalité Unicode limitée, particulièrement l'ancien type de fichier texte.

Types procéduraux

Sur la plate-forme Win32, un pointeur de procédure est stocké sous la forme d'un pointeur 32 bits sur le point d'entrée d'une procédure ou d'une fonction. Un pointeur de méthode est stocké sous la forme d'un pointeur 32 bits sur le point d'entrée d'une méthode, suivi par un pointeur 32 bits sur un objet.

Types classe

Sur la plate-forme Win32, une valeur d'un type classe est stockée sous la forme d'un pointeur 32 bits sur une instance de la classe (ce qu'on appelle aussi un objet). Le format interne d'un objet est similaire à celui d'un enregistrement. Les champs d'un objet sont stockés sous la forme d'une suite contiguë de variables, dans l'ordre de leur déclaration. Les champs sont toujours alignés, correspondant à un type enregistrement décompacté. Les champs hérités d'une classe ancêtre sont stockés avant les nouveaux champs définis dans la classe descendante.

Les 4 premiers octets de chaque objet contiennent un pointeur sur la table des méthodes virtuelles (VMT) de la classe. Il n'existe qu'une seule VMT par classe (et non une par objet), mais deux types de classes distincts ne partagent jamais une VMT, quel que soit leur degré de similitude. Les VMTs sont construites automatiquement par le compilateur et ne sont jamais manipulées directement par un programme. Les pointeurs sur les VMTs, qui sont automatiquement stockés par les méthodes constructeur dans les objets qu'elles créent, ne sont jamais directement manipulés par un programme.

Le contenu d'une VMT est présenté dans le tableau ci-dessous. Aux décalages positifs, une VMT se compose d'une liste de pointeurs de méthodes sur 32 bits, un par méthode virtuelle définie par l'utilisateur dans le type classe, dans l'ordre de la déclaration. Chaque emplacement contient l'adresse du point d'entrée de la méthode virtuelle correspondante. Cette structure est compatible avec une v-table C++ ainsi qu'avec COM. Aux décalages négatifs, une VMT contient plusieurs champs internes à Delphi. Les applications doivent utiliser les méthodes définies dans TObject pour obtenir ces informations, car cette structure pourra être amenée à changer dans les versions futures du langage Delphi.

Disposition des tables de méthodes virtuelles (Win32 seulement)

Offset Type Description

-76

Pointeur

Pointeur sur la table des méthodes virtuelles (ou nil)

-72

Pointeur

Pointeur sur la table d'interface (ou nil)

-68

Pointeur

Pointeur sur la table des informations d'automation (ou nil)

-64

Pointeur

Pointeur sur la table d'initialisation d'instance (ou nil)

-60

Pointeur

Pointeur sur la table des informations de type (ou nil)

-56

Pointeur

Pointeur sur la table de définition des champs (ou nil)

-52

Pointeur

Pointeur sur la table de définition des méthodes (ou nil)

-48

Pointeur

Pointeur sur la table des méthodes dynamiques (ou nil)

-44

Pointeur

Pointeur sur une chaîne courte contenant le nom de la classe

-40

Cardinal

Taille de l'instance en octets

-36

Pointeur

Pointeur sur un pointeur vers la classe ancêtre (ou nil)

-32

Pointeur

Pointeur sur le point d'entrée de la méthode SafecallException (ou nil)

-28

Pointeur

Point d'entrée de la méthode AfterConstruction

-24

Pointeur

Point d'entrée de la méthode BeforeDestruction

-20

Pointeur

Point d'entrée de la méthode Dispatch

-16

Pointeur

Point d'entrée de la méthode DefaultHandler

-12

Pointeur

Point d'entrée de la méthode NewInstance

-8

Pointeur

Point d'entrée de la méthode FreeInstance

-4

Pointeur

Point d'entrée du destructeur Destroy

0

Pointeur

Point d'entrée de la première méthode virtuelle définie par l'utilisateur

4

Pointeur

Point d'entrée de la seconde méthode virtuelle définie par l'utilisateur

Types références de classe

Sur la plate-forme Win32, une valeur référence de classe est stockée sous la forme d'un pointeur 32 bits sur la table des méthodes virtuelles (VMT) d'une classe.

Types variants

La discussion suivante relative aux types variants de la disposition interne s'applique uniquement à la plate-forme Win32. Les variants invoquent la conversion boxing et unboxing des données dans une enveloppe d'objet, ainsi que les classes utilitaires de Delphi pour implémenter les fonctions RTL associées aux variants.

Sur la plate-forme Win32, un variant est stocké sous la forme d'un enregistrement de 16 octets contenant un code de type et une valeur (ou une référence à une valeur), selon le type donné par le code. Les unités System et Variants définissent des constantes et des types pour les variants.

Le type TVarData représente la structure interne d'une variable Variant (sur Windows, il est identique au type Variant utilisé par COM et l'API Win32). Le type TVarData peut être utilisé dans des transtypages de variables Variant pour accéder à la structure interne d'une variable. L'enregistrement TVarData contient les champs suivants :

  • VType contient le code du type du variant dans ses 12 bits de poids faible (les bits définis par la constante varTypeMask). De plus, le bit varArray peut être défini pour indiquer que le variant est un tableau, et le bit varByRef peut être défini pour indiquer que le variant contient une référence (et non une valeur).
  • Les champs Reserved1, Reserved2 et Reserved3 ne sont pas utilisés.

Le contenu des 8 octets restants d'un enregistrement TVarData dépend du champ VType comme suit :

  • Si aucun des bits varArray ou varByRef ne sont définis, le variant contient une valeur du type donné.
  • Si le bit varArray est défini, le variant contient un pointeur sur une structure TVarArray définissant un tableau. Le type de chaque élément du tableau est donné par les bits varTypeMask du champ VType.
  • Si le bit varByRef est défini, le variant contient une référence à une valeur du type donné par les bits varTypeMask et varArray dans le champ VType.

Le code du type varString est privé. Les variants contenant une valeur varString ne devraient jamais être passés à une fonction non-Delphi. Sur Win32, le support Automation de Delphi convertit automatiquement les variants varString en variants varOleStr avant de les transmettre sous forme de paramètres aux fonctions externes.

Voir aussi

Autres langues