Dans plusieurs exemples C ++, je vois une utilisation du type size_t
où j'aurais utilisé un simple int
. Quelle est la différence et pourquoi size_t
devrait-elle être meilleure?
Dans plusieurs exemples C ++, je vois une utilisation du type size_t
où j'aurais utilisé un simple int
. Quelle est la différence et pourquoi size_t
devrait-elle être meilleure?
Réponses:
Les fichiers d'en-tête stdlib.h et stddef.h définissent un type de données appelé size_t qui est utilisé pour représenter la taille d'un objet. Les fonctions de bibliothèque qui prennent des tailles s'attendent à ce qu'elles soient de type size_t, et l'opérateur sizeof est évalué à size_t.
Le type réel de size_t dépend de la plate-forme; une erreur courante est de supposer que size_t est identique à unsigned int, ce qui peut conduire à des erreurs de programmation, d'autant plus que les architectures 64 bits deviennent plus courantes.
Vérifiez également pourquoi size_t est important
/usr/include/stdlib.h
obtient la définition à partir de laquelle /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h
elle est par défaut à long unsigned int
moins qu'un autre fichier d'en-tête ne dise le contraire.
size_t est le type utilisé pour représenter les tailles (comme son nom l'indique). Sa plate-forme (et même potentiellement sa mise en œuvre) dépendante, et ne doit être utilisée qu'à cette fin. Évidemment, représentant une taille, size_t n'est pas signé. De nombreuses fonctions stdlib, y compris malloc, sizeof et diverses fonctions d'opération de chaîne utilisent size_t comme type de données.
Un int est signé par défaut, et même si sa taille dépend également de la plate-forme, ce sera un 32 bits fixe sur la plupart des machines modernes (et bien que size_t soit 64 bits sur une architecture 64 bits, int reste 32 bits de long sur ces architectures).
Pour résumer: utilisez size_t pour représenter la taille d'un objet et int (ou long) dans les autres cas.
Le size_t
type est défini comme le type intégral non signé de l' sizeof
opérateur. Dans le monde réel, vous verrez souvent int
défini comme 32 bits (pour la compatibilité descendante) mais size_t
défini comme 64 bits (vous pouvez donc déclarer des tableaux et des structures de plus de 4 Gio) sur les plates-formes 64 bits. Si a long int
est également 64 bits, cela s'appelle la convention LP64; si long int
est 32 bits mais long long int
et les pointeurs sont 64 bits, c'est LLP64. Vous pouvez également obtenir l'inverse, un programme qui utilise des instructions 64 bits pour la vitesse, mais des pointeurs 32 bits pour économiser de la mémoire. En outre, int
est signé et size_t
n'est pas signé.
Il y avait historiquement un certain nombre d'autres plates-formes où les adresses étaient plus larges ou plus courtes que la taille native de int
. En fait, dans les années 70 et au début des années 80, c'était plus courant qu'autrement: tous les micro-ordinateurs 8 bits populaires avaient des registres 8 bits et des adresses 16 bits, et la transition entre 16 et 32 bits produisait également de nombreuses machines qui avaient des adresses plus larges que leurs registres. Je vois encore parfois des questions ici sur Borland Turbo C pour MS-DOS, dont le mode de mémoire Énorme avait des adresses 20 bits stockées en 32 bits sur un processeur 16 bits (mais qui pourrait prendre en charge le jeu d'instructions 32 bits du 80386); le Motorola 68000 avait une ALU 16 bits avec registres et adresses 32 bits; il y avait des mainframes IBM avec des adresses 15 bits, 24 bits ou 31 bits. Vous voyez également toujours différentes tailles d'ALU et de bus d'adresses dans les systèmes embarqués.
Chaque fois int
que l' heure est inférieure à size_t
, et que vous essayez de stocker la taille ou le décalage d'un fichier ou d'un objet très volumineux dans un unsigned int
, il est possible que cela déborde et provoque un bogue. Avec un int
, il y a aussi la possibilité d'obtenir un nombre négatif. Si un int
ou unsigned int
est plus large, le programme fonctionnera correctement mais gaspillera de la mémoire.
Vous devez généralement utiliser le type correct à cette fin si vous voulez la portabilité. Beaucoup de gens vous recommanderont d'utiliser des mathématiques signées au lieu de non signées (pour éviter des bogues méchants et subtils comme 1U < -3
). Pour cela, la bibliothèque standard définit ptrdiff_t
in <stddef.h>
comme le type signé du résultat de la soustraction d'un pointeur d'un autre.
Cela dit, une solution de contournement pourrait être de vérifier les limites de toutes les adresses et décalages par rapport à l' INT_MAX
un 0
ou l' autre ou INT_MIN
selon le cas, et d'activer les avertissements du compilateur concernant la comparaison des quantités signées et non signées au cas où vous en manqueriez. Vous devriez toujours, toujours, toujours vérifier vos accès aux tableaux pour un débordement en C de toute façon.
C'est parce que size_t peut être autre chose qu'un int (peut-être une structure). L'idée est qu'elle dissocie son travail du type sous-jacent.
size_t
est spécifié comme un type entier non signé . C11 §6.5.3.4 5 "La valeur du résultat des deux opérateurs ( sizeof
_Alignof
) est définie par l'implémentation et son type (un type entier non signé) est size_t
,".
La définition de SIZE_T
se trouve à:
https://msdn.microsoft.com/en-us/library/cc441980.aspx et https://msdn.microsoft.com/en-us/library/cc230394.aspx
Collez ici les informations requises:
SIZE_T
est un ULONG_PTR
représentant le nombre maximum d'octets vers lesquels un pointeur peut pointer.
Ce type est déclaré comme suit:
typedef ULONG_PTR SIZE_T;
A ULONG_PTR
est un type long non signé utilisé pour la précision du pointeur. Il est utilisé lors de la conversion d'un pointeur vers un type long pour effectuer l'arithmétique du pointeur.
Ce type est déclaré comme suit:
typedef unsigned __int3264 ULONG_PTR;
SIZE_T
n'est pas size_t
, ce que le PO a demandé.
SIZE_T
est totalement différent de size_t
. Vous ne pouvez pas déclarer une variable de type SIZE_T
.