Formats de données internes (Delphi)
Sommaire
- 1 Types entiers
- 2 Types sous-intervalle entiers
- 3 Types caractères
- 4 Types booléens
- 5 Types énumérés
- 6 Types réels
- 7 Types pointeur
- 8 Types chaînes courtes
- 9 Types chaîne longue
- 10 Types chaîne étendue
- 11 Types ensemble
- 12 Types tableau statique
- 13 Types tableau dynamique
- 14 Types enregistrement
- 15 Types de fichiers
- 16 Types procéduraux
- 17 Types classe
- 18 Types référence de classe
- 19 Types variants
- 20 Voir aussi
Remonter à Gestion de la mémoire - Index
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.
Word et UInt16
Word et UInt16 sont des nombres entiers non signés sur 2 octets (16 bits).
FixedUInt, Cardinal et UInt32
FixedUInt, Cardinal et UInt32 sont des nombres entiers non signés sur 4 octets (32 bits).
UInt64
UInt64 sont des nombres entiers non signés sur 8 octets (64 bits).
Types entiers signés indépendants de la plate-forme
Les valeurs des types entiers signés représentent 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 :
- En partant de la droite, trouvez le premier '1'.
- 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
|
0101011
|
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.
SmallInt et Int16
SmallInt et Int16 sont des nombres entiers signés sur 2 octets (16 bits).
FixedInt, Integer et Int32
FixedInt, Integer et Int32 sont des nombres entiers signés sur 4 octets (32 bits).
Int64
Int64 sont des nombres entiers signés sur 8 octets (64 bits).
Types entiers dépendants de la plate-forme
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 (à l'exception des types LongInt et LongWord). 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épendent 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épendent 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.
LongInt et LongWord
LongInt définit le type entier signé et LongWord définit le type entier non signé. La taille des types entiers LongInt et LongWord dépendant de la plate-forme est modifiée selon la plate-forme, à l'exception de Windows 64 bits où la taille reste inchangée (32 bits).
Taille | ||
---|---|---|
Plates-formes Windows 32 bits et 64 bits | Plates-formes iOS 64 bits | |
LongInt | 32 bits (4 octets) | 64 bits (8 octets) |
LongWord |
32 bits (4 octets) | 64 bits (8 octets) |
Sur les plates-formes iOS 64 bits, si vous voulez utiliser :
Types sous-intervalle entiers
Lorsque 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 (FixedInt et LongInt sur les plates-formes Windows 32 bits et 64 bits), la variable est stockée sous la forme d'un double mot signé.
- Si les deux bornes sont contenues dans l'intervalle 0..4294967295 (FixedUInt et LongWord sur les plates-formes Windows 32 bits et 64 bits), la variable est stockée sous la forme d'un double mot non signé.
- Si les deux bornes sont contenues dans l'intervalle -2^63..2^63-1 (Int64 et LongInt sur les plates-formes iOS 64 bits), la variable est stockée sous la forme d'un quadruple mot signé.
- Si les deux bornes sont contenues dans l'intervalle 0..2^64-1 (UInt64 et LongWord sur les plates-formes iOS 64 bits), la variable est stockée sous la forme d'un quadruple mot non signé.
Types caractères
Sur les plates-formes 32 bits et 64 bits :
- Char etWideChar sont stockés sous la forme d'une variable d'un mot non signé, en utilisant normalement l'encodage UTF-16 ou Unicode.
- Le type AnsiChar est stocké 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 un comptage 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 type 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 peuvent prendre les valeurs 0 (False) ou toute valeur différente de zéro (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é dans l'état {$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
où 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 32 bits et 64 bits, un nombre Real48 sur 6 octets (48 bits) est décomposé en trois champs :
1 |
39 |
8 |
|
|
|
Si 0 < e <= 255
, la valeur v
du nombre est donnée par la formule :
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 (Inf). 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
Sur les plates-formes 32 bits et 64 bits, un nombre Single sur 4 octets (32 bits) est décomposé en trois champs :
1 |
8 |
23 |
|
|
|
La valeur v
du nombre est donnée par la formule :
- Si
0 < e < 255
, puisv = (-1)s * 2(e-127) * (1.f)
- Si
e = 0
etf <> 0
, alorsv = (-1)s * 2(-126) * (0.f)
- Si
e = 0
etf = 0
, alorsv = (-1)s * 0
- Si
e = 255
etf = 0
, alorsv = (-1)s * Inf
- Si
e = 255
etf <> 0
, alorsv
est un NaN
Le type Double
Le type Real est équivalent, dans son implémentation actuelle, au type Double.
Sur les plates-formes 32 bits et 64 bits, un nombre Double sur 8 octets (64 bits) est décomposé en trois champs.
1 |
11 |
52 |
|
|
|
La valeur v
du nombre est donnée par la formule :
- Si
0 < e < 2047
, alorsv = (-1)s * 2(e-1023) * (1.f)
- Si
e = 0
etf <> 0
, alorsv = (-1)s * 2(-1022) * (0.f)
- Si
e = 0
etf = 0
, alorsv = (-1)s * 0
- Si
e = 2047
andf = 0
, alorsv = (-1)s * Inf
- Si
e = 2047
andf <> 0
, alorsv
est un NaN.
Le type Extended
Extended offre une plus grande précision sur la plate-forme Intel 32 bits que les autres types réels, mais il est moins portable. Evitez d'utiliser Extended si vous créez des fichiers de données qui doivent être partagés sur plusieurs plates-formes. Faites attention :
Sur la plate-forme Intel 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 |
|
|
|
|
La valeur v
du nombre est donnée par la formule :
- Si
0 <= e < 32767
, alorsv = (-1)s * 2(e-16383) * (i.f)
- Si
e = 32767
etf = 0
, alorsv = (-1)s * Inf
- Si
e = 32767
etf <> 0
, alorsv
est un NaN
Sur la plate-forme Intel 64 bits et la plate-forme ARM, le type Extended est un alias pour Double, qui est seulement de 8 octets. Cette différence peut avoir une incidence sur la précision numérique dans les opérations à virgule flottante. Pour de plus amples informations, voir Considérations Delphi pour les applications multi-périphériques. Sur les systèmes macOS, la taille de Extended est désormais de 16 octets pour être compatible avec BCCOSX.
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 ShortString occupe le nombre d'octets correspondant à sa longueur maximale plus un. Le premier octet contient la longueur dynamique en cours 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îne longue
Une variable chaîne de type UnicodeString ou AnsiString occupe 4 octets de mémoire sur les plates-formes 32 bits (et 8 octets sur 64 bits) 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 à 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. Les tableaux suivants présentent l'organisation d'un bloc mémoire de chaîne longue.
Format du type de données UnicodeString (32 bits et 64 bits)
Champ | Page de code | Taille d'élément | Compteur de références | Longueur | Données chaîne (dimensionnées en éléments) |
Terme Null |
---|---|---|---|---|---|---|
Décalage |
|
|
|
|
|
|
Contenu |
Page de code 16 bits de données chaîne |
Taille d'élément 16 bits de données chaîne |
Compte de références sur 32 bits |
Longueur en caractères |
Chaîne de caractères de données dimensionnées en éléments |
Caractère NULL |
Les nombres de la ligne Décalage montrent les décalages de champs, décrivant le contenu de la chaîne, du pointeur de chaîne, qui pointe sur le champ Données chaîne (offset = 0
), contenant un bloc de mémoire qui contient les valeurs de la chaîne réelle.
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 terminée par null.
Voir aussi "Nouveau type de chaîne : UnicodeString."
Pour les littéraux chaîne, le compilateur génère un bloc mémoire de même organisation 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. Les deux pointeurs, source et destination, pointeront sur le même bloc mémoire après l'assignation.
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 n'est 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.
Types chaîne étendue
Sur les plates-formes 32 bits, une variable chaîne étendue occupe 4 octets de mémoire (et 8 octets sur 64 bits) qui contiennent un pointeur sur une chaîne allouée dynamiquement. Lorsqu'une variable chaîne étendue est vide (contient une chaîne de longueur zéro), le pointeur de chaîne est nil et aucune mémoire dynamique n'est associée à 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 l'organisation d'un bloc mémoire de chaîne étendue sur Windows.
Organisation en mémoire dynamique d'une chaîne étendue (32 bits et 64 bits)
Décalage |
|
|
|
Contenu |
Indicateur de longueur sur 32 bits |
Chaîne de caractères |
Caractère NULL |
La longueur de la chaîne est évaluée en octets, c'est donc le double du nombre de caractères étendus 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 terminée par null.
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
où 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
où 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 dépendant de la plate-forme ou si le programme contient du code qui utilise l'adresse de l'ensemble.
Types tableau statique
La mémoire occupée par une variable de tableau statique est définie en calculant Length(array) * SizeOf(array[Low(array)]) en octets. La variable de tableau statique est entièrement allouée en tant que structure des données parent. Un tableau statique est stocké sous la forme d'une séquence contiguë d'éléments du type composant du tableau. Les composants avec les plus faibles index 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 tableau dynamique
Sur la plate-forme 32 bits, une variable tableau dynamique occupe 4 octets de mémoire (et 8 octets sur 64 bits) qui contiennent un pointeur sur le tableau alloué dynamiquement. Quand la variable est vide (non initialisée) ou contient un tableau de longueur zéro, 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 (64 bits sur Win64) et un compte de références sur 32 bits. Le tableau suivant indique l'organisation du bloc de mémoire de tableau dynamique.
Organisation en mémoire d'un tableau dynamique (32 bits et 64 bits)
Décalage 32 bits |
|
|
|
Décalage 64 bits |
|
|
|
Contenu |
Compte de références sur 32 bits |
|
Eléments du tableau |
Types enregistrement
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 (32 bits 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îne courte |
1 |
Types tableau |
Identique au type des éléments du tableau |
Types enregistrement |
Le plus grand alignement des champs de l'enregistrement |
Types ensemble |
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.
Lorsqu'un type enregistrement est déclaré dans l'état {$A-}
ou lorsque la déclaration comprend le modificateur packed, les champs de l'enregistrement ne sont pas alignés, mais des déplacements consécutifs leur sont plutôt affecté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
Les types fichier sont représentés sous forme d'enregistrements. Les fichiers typés et non typés occupent 592 octets sur les plates-formes 32 bits et 616 octets sur les plates-formes 64 bits, disposés comme suit :
type
TFileRec = packed record
Handle: NativeInt;
Mode: word;
Flags: word;
case Byte of
0: (RecSize: Cardinal);
1: (BufSize: Cardinal;
BufPos: Cardinal;
BufEnd: Cardinal;
BufPtr: _PAnsiChr;
OpenFunc: Pointer;
InOutFunc: Pointer;
FlushFunc: Pointer;
CloseFunc: Pointer;
UserData: array[1..32] of Byte;
Name: array[0..259] of WideChar; );
end;
Les fichiers texte occupent 730 octets sur Win32 et 754 octets sur Win64, disposés comme suit :
type
TTextBuf = array[0..127] of Char;
TTextRec = packed record
Handle: NativeInt;
Mode: word;
Flags: word;
BufSize: Cardinal;
BufPos: Cardinal;
BufEnd: Cardinal;
BufPtr: _PAnsiChr;
OpenFunc: Pointer;
InOutFunc: Pointer;
FlushFunc: Pointer;
CloseFunc: Pointer;
UserData: array[1..32] of Byte;
Name: array[0..259] of WideChar;
Buffer: TTextBuf; //
CodePage: Word;
MBCSLength: ShortInt;
MBCSBufPos: Byte;
case Integer of
0: (MBCSBuffer: array[0..5] of _AnsiChr);
1: (UTF16Buffer: array[0..2] of WideChar);
end;
Handle
contient le handle du fichier (quand celui-ci est ouvert).
Le champ Mode
peut prendre l'une des valeurs suivantes :
const
fmClosed = $D7B0;
fmInput= $D7B1;
fmOutput = $D7B2;
fmInOut= $D7B3;
où 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é assigné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 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. Pour davantage d'informations, 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.
Types procéduraux
Sur la plate-forme 32 bits, 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.
Sur la plate-forme 64 bits, un pointeur de procédure est stocké sous la forme d'un pointeur 64 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 64 bits sur le point d'entrée d'une méthode, suivi par un pointeur 64 bits sur un objet.
Types classe
Sur les plates-formes 32 bits (Win32, macOS, iOS et Android), une valeur de type classe est stockée sous la forme d'un pointeur 32 bits sur une instance de la classe (et d'un pointeur 64 bits sur la plate-forme 64 bits), qui est appelée un objet. Le format de données interne d'un objet est similaire à celui d'un enregistrement. Les champs de l'objet sont stockés dans l'ordre de déclaration sous la forme d'une séquence de variables contiguës. Les champs sont toujours alignés, correspondant à un type enregistrement décompacté. Par conséquent, l'alignement correspond au plus grand alignement des champs dans l'objet. Les champs hérités d'une classe ancêtre sont stockés avant les nouveaux champs définis dans la classe descendante.
Sur les plates-formes 32 bits, le premier champ sur 4 octets de chaque objet (le premier champ sur 8 octets sur la plate-forme 64 bits) est 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 VMT sont construites automatiquement par le compilateur et ne sont jamais manipulées directement par un programme. Les pointeurs sur les VMT, 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.
L'organisation d'une VMT est présentée dans le tableau ci-dessous. Sur les plates-formes 32 bits, aux décalages positifs, une VMT se compose d'une liste de pointeurs de méthodes sur 32 bits (pointeurs de méthodes sur 64 bits sur la plate-forme 64 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 organisation est compatible avec une v-table C++ ainsi qu'avec COM. Aux décalages négatifs, une VMT contient un certain nombre de champs qui sont internes à l'implémentation de Delphi. Les applications doivent utiliser les méthodes définies dans TObject pour interroger ces informations, car cette organisation pourra être amenée à changer dans les versions futures du langage Delphi.
Disposition des tables de méthodes virtuelles
Décalage Win32, macOS |
Décalage Win64 |
Décalage iOS/ARM, Android/ARM |
Type | Description | Constante dans System.pas |
---|---|---|---|---|---|
-88 |
-200 |
-108 |
Pointeur |
Pointeur sur la table des méthodes virtuelles (ou nil) |
vmtSelfPtr |
-84 |
-192 |
-104 |
Pointeur |
Pointeur sur la table d'interface (ou nil) |
vmtIntfTable |
-80 |
-184 |
-100 |
Pointeur |
Pointeur sur la table des informations d'automation (ou nil) |
vmtAutoTable |
-76 |
-176 |
-96 |
Pointeur |
Pointeur sur la table d'initialisation d'instance (ou nil) |
vmtInitTable |
-72 |
-168 |
-92 |
Pointeur |
Pointeur sur la table des informations de type (ou nil) |
vmtTypeInfo |
-68 |
-160 |
-88 |
Pointeur |
Pointeur sur la table de définition des champs (ou nil) |
vmtFieldTable |
-64 |
-152 |
-84 |
Pointeur |
Pointeur sur la table de définition des méthodes (ou nil) |
vmtMethodTable |
-60 |
-144 |
-80 |
Pointeur |
Pointeur sur la table des méthodes dynamiques (ou nil) |
vmtDynamicTable |
-56 |
-136 |
-76 |
Pointeur |
Pointeur sur une chaîne courte contenant le nom de la classe |
vmtClassName |
-52 |
-128 |
-72 |
Cardinal |
Taille de l'instance en octets |
vmtInstanceSize |
-48 |
-120 |
-68 |
Pointeur |
Pointeur sur un pointeur vers la classe ancêtre (ou nil) |
vmtParent |
n/a |
n/a |
-64 |
Pointeur |
Point d'entrée de la méthode __ObjAddRef |
vmtObjAddRef |
n/a |
n/a |
-60 |
Pointeur |
Point d'entrée de la méthode __ObjRelease |
vmtObjRelease |
-44 |
-112 |
-56 |
Pointeur |
Point d'entrée de la méthode Equals |
vmtEquals |
-40 |
-104 |
-52 |
Pointeur |
Point d'entrée de la méthode GetHashCode |
vmtGetHashCode |
-36 |
-96 |
-48 |
Pointeur |
Point d'entrée de la méthode ToString |
vmtToString |
-32 |
-88 |
-44 |
Pointeur |
Pointeur sur le point d'entrée de la méthode SafecallException (ou nil) |
vmtSafeCallException |
-28 |
-80 |
-40 |
Pointeur |
Point d'entrée de la méthode AfterConstruction |
vmtAfterConstruction |
-24 |
-72 |
-36 |
Pointeur |
Point d'entrée de la méthode BeforeDestruction |
vmtBeforeDestruction |
-20 |
-64 |
-32 |
Pointeur |
Point d'entrée de la méthode Dispatch |
vmtDispatch |
-16 |
-56 |
-28 |
Pointeur |
Point d'entrée de la méthode DefaultHandler |
vmtDefaultHandler |
-12 |
-48 |
-24 |
Pointeur |
Point d'entrée de la méthode NewInstance |
vmtNewInstance |
-8 |
-40 |
-20 |
Pointeur |
Point d'entrée de la méthode FreeInstance |
vmtFreeInstance |
-4 |
-32 |
-16 |
Pointeur |
Point d'entrée du destructeur Destroy |
vmtDestroy |
0 |
0 |
0 |
Pointeur |
Point d'entrée de la première méthode virtuelle définie par l'utilisateur |
|
4 |
8 |
4 |
Pointeur |
Point d'entrée de la deuxième méthode virtuelle définie par l'utilisateur |
Types référence de classe
Sur la plate-forme 32 bits (Win32, macOS, iOS et Android), 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.
Sur la plate-forme 64 bits (Win64), une valeur référence de classe est stockée sous la forme d'un pointeur 64 bits sur la table des méthodes virtuelles (VMT) d'une classe.
Types variants
Les variants invoquent la conversion boxing et unboxing des données dans un wrapper d'objet, ainsi que les classes d'assistance de Delphi pour implémenter les fonctions RTL associées aux variants.
Sur la plate-forme 32 bits, 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. Sur la plate-forme 64 bits, un variant est stocké sous la forme d'un enregistrement de 24 octets. Les unités System et System.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 :
- Le champ VType du type TVarType a la taille Word (16 bits). VType contient le code de type du variant dans ses 12 bits de poids faible (les bits définis par la constante varTypeMask
= $FFF
). De plus, le bit varArray= $2000
peut être défini pour indiquer que le variant est un tableau, et le bit varByRef (= $4000
) peut être défini pour indiquer que le variant contient une référence (et non une valeur). - Les champs Reserved1, Reserved2 et Reserved3 (taille Word) sont inutilisés.
Le contenu des 8 octets (plate-forme 32 bits) ou 16 octets (plate-forme 64 bits) restants d'un enregistrement TVarData dépend du champ VType comme suit :
- Si aucun des bits varArray et varByRef n'est défini, le variant contient une valeur du type donné.
- Si le bit varArray est défini, le variant contient un pointeur sur une structure TVarArray qui définit un tableau. Le type de chaque élément de tableau est donné par les bits varTypeMask dans le 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 de type varString est privé. Les variants contenant une valeur varString ne doivent jamais être transmis à une fonction non Delphi. Sur la plate-forme Windows, le support Automation de Delphi effectue automatiquement la conversion des variants varString en variants varOleStr avant de les transmettre sous forme de paramètres aux fonctions externes.