Réponses:
Le size_t
type est le type entier non signé qui est le résultat de l' sizeof
opérateur (et de l' offsetof
opérateur), il est donc garanti d'être suffisamment grand pour contenir la taille du plus grand objet que votre système peut gérer (par exemple, un tableau statique de 8 Go).
Le size_t
type peut être supérieur, égal ou inférieur à an unsigned int
, et votre compilateur peut faire des hypothèses à ce sujet pour l'optimisation.
Vous pouvez trouver des informations plus précises dans la norme C99, section 7.17, dont un projet est disponible sur Internet au format pdf , ou dans la norme C11, section 7.19, également disponible en version pdf .
size_t
peut représenter! Si ce n'est pas le cas, qui le fait?
Le C classique (le premier dialecte du C décrit par Brian Kernighan et Dennis Ritchie dans The C Programming Language, Prentice-Hall, 1978) n'a pas fourni size_t
. Introduction du comité des normes C size_t
pour éliminer un problème de portabilité
Expliqué en détail sur embedded.com (avec un très bon exemple)
En bref, il size_t
n'est jamais négatif et optimise les performances car il est typé comme étant le type entier non signé qui est assez grand - mais pas trop grand - pour représenter la taille du plus grand objet possible sur la plate-forme cible.
Les tailles ne doivent jamais être négatives et sont en effet size_t
un type non signé. De plus, parce qu'il size_t
n'est pas signé, vous pouvez stocker des nombres qui sont environ deux fois plus gros que dans le type signé correspondant, car nous pouvons utiliser le bit de signe pour représenter la magnitude, comme tous les autres bits de l'entier non signé. Lorsque nous gagnons un bit de plus, nous multiplions la plage de nombres que nous pouvons représenter par un facteur d'environ deux.
Alors, demandez-vous, pourquoi ne pas simplement utiliser un unsigned int
? Il peut ne pas être en mesure de contenir des nombres suffisamment importants. Dans une implémentation où unsigned int
est 32 bits, le plus grand nombre qu'il peut représenter est 4294967295
. Certains processeurs, tels que l'IP16L32, peuvent copier des objets plus grands que les 4294967295
octets.
Alors, demandez-vous, pourquoi ne pas utiliser un unsigned long int
? Il impose un péage de performance sur certaines plates-formes. La norme C exige qu’une long
occupe au moins 32 bits. Une plate-forme IP16L32 implémente chaque 32 bits de long comme une paire de mots de 16 bits. Presque tous les opérateurs 32 bits sur ces plates-formes nécessitent deux instructions, sinon plus, car ils fonctionnent avec les 32 bits dans deux blocs 16 bits. Par exemple, le déplacement d'une longueur de 32 bits nécessite généralement deux instructions machine - une pour déplacer chaque bloc de 16 bits.
L'utilisation size_t
évite ce péage de performance. Selon cet article fantastique , "Type size_t
est un typedef qui est un alias pour un type d'entier non signé, généralement unsigned int
ou unsigned long
, mais peut-être même unsigned long long
. Chaque implémentation Standard C est censée choisir l'entier non signé qui est assez grand - mais pas plus grand que nécessaire - pour représenter la taille du plus grand objet possible sur la plate-forme cible. "
unsigned int
boîte et varie d'un système à l'autre. Il doit être au moins 65536
, mais il est courant 4294967295
et pourrait être 18446744073709551615
(2 ** 64-1) sur certains systèmes.
unsigned char
). La norme ne semble pas contenir la chaîne '65535' ou '65536' n'importe où, et '+32767' ne se produit que (1.9: 9) dans une note comme le plus grand entier possible représentable dans int
; aucune garantie n'est donnée même qui INT_MAX
ne peut être inférieure à cela!
Le type size_t est le type renvoyé par l'opérateur sizeof. Il s'agit d'un entier non signé capable d'exprimer la taille en octets de n'importe quelle plage de mémoire prise en charge sur la machine hôte. Il est (généralement) lié à ptrdiff_t en ce que ptrdiff_t est une valeur entière signée telle que sizeof (ptrdiff_t) et sizeof (size_t) sont égaux.
Lors de l'écriture de code C, vous devez toujours utiliser size_t lorsque vous traitez avec des plages de mémoire.
Le type int, d'autre part, est essentiellement défini comme la taille de la valeur entière (signée) que la machine hôte peut utiliser pour effectuer le plus efficacement l'arithmétique entière. Par exemple, sur de nombreux ordinateurs de type PC plus anciens, la valeur sizeof (size_t) serait de 4 (octets) mais sizeof (int) serait de 2 (octets). L'arithmétique 16 bits était plus rapide que l'arithmétique 32 bits, bien que le CPU puisse gérer un espace mémoire (logique) allant jusqu'à 4 Gio.
N'utilisez le type int que lorsque vous vous souciez de l'efficacité car sa précision réelle dépend fortement des options du compilateur et de l'architecture de la machine. En particulier, la norme C spécifie les invariants suivants: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) ne plaçant aucune autre limitation sur la représentation réelle de la précision disponible pour le programmeur pour chacun des ces types primitifs.
Remarque: ce n'est PAS la même chose qu'en Java (qui spécifie en fait la précision des bits pour chacun des types 'char', 'byte', 'short', 'int' et 'long').
size_t
est capable de représenter la taille de n'importe quel objet (par exemple: nombre, tableau, structure). L'ensemble de la plage de mémoire peut dépassersize_t
size_t
- j'espère que vous ne le pensez pas. La plupart du temps, nous ne traitons pas de tableaux où la cardinalité de l'espace d'adressage + la portabilité comptent même. Dans ces cas, vous prendriez size_t
. Dans tous les autres cas, vous retirez les indices d'entiers (signés). Parce que la confusion (qui vient sans avertissement) provenant d'un comportement de sous-dépassement insoupçonné des non signés est plus courante et pire que les problèmes de portabilité qui peuvent survenir dans les autres cas.
Le type size_t doit être suffisamment grand pour stocker la taille de tout objet possible. Un entier non signé ne doit pas remplir cette condition.
Par exemple, dans les systèmes 64 bits int et unsigned int peuvent avoir une largeur de 32 bits, mais size_t doit être suffisamment grand pour stocker des nombres supérieurs à 4G
size_t
cela ne devrait être aussi gros que si le compilateur pouvait accepter un type X tel que sizeof (X) donnerait une valeur supérieure à 4G. La plupart des compilateurs rejetteraient par exemple typedef unsigned char foo[1000000000000LL][1000000000000LL]
, et foo[65536][65536];
pourraient même être légitimement rejetés s'ils dépassaient une limite documentée définie par l'implémentation.
Cet extrait du manuel glibc 0.02 peut également être pertinent lors de la recherche sur le sujet:
Il existe un problème potentiel avec le type size_t et les versions de GCC avant la version 2.4. ANSI C requiert que size_t soit toujours un type non signé. Pour la compatibilité avec les fichiers d'en-tête des systèmes existants, GCC définit size_t dansstddef.h' to be whatever type the system's
sys / types.h 'le définit. La plupart des systèmes Unix qui définissent size_t dans `sys / types.h ', le définissent comme un type signé. Un certain code dans la bibliothèque dépend de la taille de size_t comme un type non signé et ne fonctionnera pas correctement s'il est signé.
Le code de bibliothèque GNU C qui s'attend à ce que size_t ne soit pas signé est correct. La définition de size_t en tant que type signé est incorrecte. Nous prévoyons que dans la version 2.4, GCC définira toujours size_t comme un type non signé, etfixincludes' script will massage the system's
sys / types.h 'afin de ne pas entrer en conflit avec cela.
En attendant, nous contournons ce problème en disant explicitement à GCC d'utiliser un type non signé pour size_t lors de la compilation de la bibliothèque GNU C. `configure 'détectera automatiquement le type utilisé par GCC pour size_t afin de le remplacer si nécessaire.
Si mon compilateur est réglé sur 32 bits, size_t
n'est rien d'autre qu'un typedef pour unsigned int
. Si mon compilateur est réglé sur 64 bits, size_t
n'est rien d'autre qu'un typedef pour unsigned long long
.
unsigned long
pour les deux cas sur certains systèmes d'exploitation.
size_t est la taille d'un pointeur.
Donc en 32 bits ou le modèle commun ILP32 (entier, long, pointeur) size_t est de 32 bits. et en 64 bits ou le modèle commun LP64 (long, pointeur) size_t est de 64 bits (les entiers sont toujours de 32 bits).
Il existe d'autres modèles mais ce sont ceux que g ++ utilise (au moins par défaut)
size_t
n'est pas nécessairement de la même taille qu'un pointeur, bien qu'il le soit généralement. Un pointeur doit pouvoir pointer vers n'importe quel emplacement en mémoire; size_t
doit seulement être assez grand pour représenter la taille du plus grand objet unique.