Je m'embrouille avec size_t
en C. Je sais qu'il est retourné par l' sizeof
opérateur. mais qu'est ce que c'est exactement? S'agit-il d'un type de données?
Disons que j'ai une for
boucle:
for(i = 0; i < some_size; i++)
Dois-je utiliser int i;
ou size_t i;
?
int
sisome_size
est signé,size_t
s'il n'est pas signé.int i
peut ne pas être suffisante pour traiter un énorme tableau. Donc, en utilisant,size_t i
vous pouvez adresser plus d'indices, donc même si vous avez un énorme tableau qui ne devrait pas être un problème.size_t
est un type de données: généralement ununsigned long int
mais cela dépend de votre système.Réponses:
De Wikipédia :
Comme implication,
size_t
est un type garanti pour contenir n'importe quel index de tableau.la source
size_t
est pour les objets en mémoire. La norme C ne définit même passtat()
ouoff_t
(ce sont des définitions POSIX) ou quoi que ce soit à voir avec les disques ou les systèmes de fichiers - elle s'arrête auxFILE
flux. La gestion de la mémoire virtuelle est complètement différente des systèmes de fichiers et de la gestion des fichiers en ce qui concerne les exigences de taille, donc la mentionoff_t
n'est pas pertinente ici.size_t
comme le type du résultat de l'sizeof
opérateur (7.17p2 environ<stddef.h>
). La section 6.5 explique exactement comment fonctionnent les expressions C (6.5.3.4 poursizeof
). Étant donné que vous ne pouvez pas appliquersizeof
à un fichier disque (principalement parce que C ne définit même pas le fonctionnement des disques et des fichiers), il n'y a pas de place pour la confusion. En d'autres termes, blâmez Wikipédia (et cette réponse pour avoir cité Wikipédia et non la norme C réelle).size_t
est un type non signé. Ainsi, il ne peut représenter aucune valeur négative (<0). Vous l'utilisez lorsque vous comptez quelque chose et êtes sûr qu'il ne peut pas être négatif. Par exemple,strlen()
renvoie asize_t
car la longueur d'une chaîne doit être d'au moins 0.Dans votre exemple, si votre index de boucle va toujours être supérieur à 0, il peut être judicieux d'utiliser
size_t
, ou tout autre type de données non signé.Lorsque vous utilisez un
size_t
objet, vous devez vous assurer que dans tous les contextes où il est utilisé, y compris l'arithmétique, vous souhaitez des valeurs non négatives. Par exemple, supposons que vous ayez:et vous voulez trouver la différence des longueurs de
str2
etstr1
. Tu ne peux pas faire:En effet, la valeur affectée à
diff
sera toujours un nombre positif, même lorsques2 < s1
, car le calcul est effectué avec des types non signés. Dans ce cas, en fonction de votre cas d'utilisation, il est préférable d'utiliserint
(oulong long
) pours1
ets2
.Certaines fonctions de C / POSIX pourraient / devraient être utilisées
size_t
, mais pas pour des raisons historiques. Par exemple, le deuxième paramètre àfgets
devrait idéalement êtresize_t
, mais il l'estint
.la source
size_t
? 2) pourquoi devrais-je préférersize_t
quelque chose commeunsigned int
?size_t
estsizeof(size_t)
. La norme C garantit que ceSIZE_MAX
sera au moins 65535.size_t
est le type retourné par l'sizeof
opérateur, et est utilisé dans la bibliothèque standard (par exemplestrlen
retourssize_t
). Comme l'a dit Brendan, ilsize_t
n'est pas nécessaire que ce soit le même queunsigned int
.size_t
est garanti qu'il s'agit d'un type non signé.s2 - s1
déborde unint
, le comportement n'est pas défini.size_t
est un type qui peut contenir n'importe quel index de tableau.Selon l'implémentation, il peut s'agir de:
unsigned char
unsigned short
unsigned int
unsigned long
unsigned long long
Voici comment
size_t
est défini dansstddef.h
ma machine:la source
typedef unsigned long size_t
dépend certainement du compilateur. Ou suggérez-vous qu'il en soit toujours ainsi?unsigned long
est 32 bits,size_t
est 64 bits.size_t
n'est pas une variable. C'est un type que vous pouvez utiliser lorsque vous souhaitez représenter la taille d'un objet en mémoire.size_t
c'est toujours 32 bits sur une machine 32 bits, 64 bits également?Si vous êtes du type empirique ,
Sortie pour Ubuntu 14.04 64-bit GCC 4.8:
Notez que cela
stddef.h
est fourni par GCC et non par la glibcsrc/gcc/ginclude/stddef.h
dans GCC 4.2.Apparitions C99 intéressantes
malloc
prendsize_t
comme argument, il détermine donc la taille maximale qui peut être allouée.Et comme il est également renvoyé par
sizeof
, je pense qu'il limite la taille maximale de tout tableau.Voir aussi: Quelle est la taille maximale d'un tableau en C?
la source
size_t
est , au moins sur une distro Linux populaire.La page de manuel de types.h indique:
la source
Puisque personne ne l'a encore mentionné, la signification linguistique principale de
size_t
est que l'sizeof
opérateur renvoie une valeur de ce type. De même, la signification principale deptrdiff_t
est que la soustraction d'un pointeur à un autre donnera une valeur de ce type. Les fonctions de bibliothèque qui l'acceptent le font car cela permettra à ces fonctions de fonctionner avec des objets dont la taille dépasse UINT_MAX sur les systèmes où de tels objets pourraient exister, sans forcer les appelants à perdre du code en passant une valeur supérieure à "unsigned int" sur les systèmes où le type plus grand suffirait pour tous les objets possibles.la source
malloc()
. Personnellement, j'aurais aimé voir des versions qui prennent des arguments de typeint
,long
etlong long
, avec certaines implémentations favorisant des types plus courts et d'autres implémentant par exemplelmalloc(long n) {return (n < 0 || n > 32767) ? 0 : imalloc(n);}
[sur certaines plates-formes, appeler àimalloc(123)
serait moins cher que d'appelerlmalloc(123);
, et même sur une plate-forme oùsize_t
est 16 bits, code qui veut allouer une taille calculée dans une valeur "longue" ...Pour expliquer pourquoi il
size_t
fallait exister et comment nous en sommes arrivés là:En termes pragmatiques,
size_t
etptrdiff_t
sont garantis à 64 bits de large sur une implémentation 64 bits, 32 bits de large sur une implémentation 32 bits, et ainsi de suite. Ils ne pouvaient forcer aucun type existant à signifier cela, sur chaque compilateur, sans casser le code hérité.Un
size_t
ouptrdiff_t
n'est pas nécessairement le même qu'unintptr_t
ouuintptr_t
. Ils étaient différents sur certaines architectures qui étaient encore en usage quandsize_t
etptrdiff_t
ont été ajoutés à la norme à la fin des années 80, et devenant obsolètes lorsque C99 a ajouté de nombreux nouveaux types mais pas encore disparus (tels que Windows 16 bits). Le x86 en mode protégé 16 bits avait une mémoire segmentée où la plus grande matrice ou structure possible ne pouvait avoir qu'une taille de 65 536 octets, mais unfar
pointeur devait avoir une largeur de 32 bits, plus large que les registres. Sur ceux-ci,intptr_t
aurait été de 32 bits de large maissize_t
etptrdiff_t
pourrait avoir une largeur de 16 bits et rentrer dans un registre. Et qui savait quel type de système d'exploitation pourrait être écrit à l'avenir? En théorie, l'architecture i386 propose un modèle de segmentation 32 bits avec des pointeurs 48 bits qu'aucun système d'exploitation n'a jamais réellement utilisé.Le type d'un décalage de mémoire ne peut pas être
long
dû au fait que trop de code hérité suppose unelong
largeur exacte de 32 bits. Cette hypothèse a même été intégrée aux API UNIX et Windows. Malheureusement, beaucoup d'autres codes hérités supposaient également que along
est suffisamment large pour contenir un pointeur, un décalage de fichier, le nombre de secondes qui se sont écoulées depuis 1970, etc. POSIX fournit désormais un moyen normalisé de forcer la dernière hypothèse à être vraie au lieu de la première, mais aucune hypothèse portable n'est à faire.Cela ne pouvait pas être
int
parce que seule une petite poignée de compilateurs dans les années 90 faisaientint
64 bits de large. Ensuite, ils sont vraiment devenus étranges en gardant unelong
largeur de 32 bits. La prochaine révision de la norme l'a déclarée illégale pourint
être plus large quelong
, mais elleint
est toujours de 32 bits sur la plupart des systèmes 64 bits.Il ne pouvait pas l'être
long long int
, ce qui a été ajouté de toute façon plus tard, car il a été créé pour être d'au moins 64 bits, même sur les systèmes 32 bits.Donc, un nouveau type était nécessaire. Même si ce n'était pas le cas, tous ces autres types signifiaient autre chose qu'un décalage dans un tableau ou un objet. Et s'il y avait une leçon à tirer du fiasco de la migration de 32 à 64 bits, c'était de préciser les propriétés qu'un type devait avoir et de ne pas en utiliser une qui signifiait différentes choses dans différents programmes.
la source
size_t
etptrdiff_t
sont garantis à 64 bits de large sur une implémentation 64 bits", etc. La garantie est surestimée. La plage desize_t
est principalement déterminée par la capacité de mémoire de l'implémentation. "une implémentation de n bits" est principalement la largeur du processeur natif des entiers. De nombreuses implémentations utilisent certainement une taille de mémoire et une largeur de bus de processeur similaires, mais des entiers natifs larges avec une mémoire insuffisante ou des processeurs étroits avec beaucoup de mémoire existent et séparent ces deux propriétés d'implémentation.size_t
etint
ne sont pas interchangeables. Par exemple, sur 64 bits, Linux a unesize_t
taille de 64 bits (c'est-à-diresizeof(void*)
) maisint
est de 32 bits.Notez également que ce
size_t
n'est pas signé. Si vous avez besoin d'une version signée, il y en assize_t
sur certaines plates-formes et cela serait plus pertinent pour votre exemple.En règle générale, je suggérerais d'utiliser la
int
plupart des cas généraux et de n'utilisersize_t
/ quessize_t
lorsqu'il y a un besoin spécifique (avecmmap()
par exemple).la source
En général, si vous commencez à 0 et montez, utilisez toujours un type non signé pour éviter un débordement vous entraînant dans une situation de valeur négative. Ceci est extrêmement important, car si les limites de votre tableau s'avèrent être inférieures au maximum de votre boucle, mais que votre maximum de boucle se trouve être supérieur au maximum de votre type, vous passerez à négatif et vous pourrez rencontrer une erreur de segmentation (SIGSEGV ). Donc, en général, n'utilisez jamais int pour une boucle commençant à 0 et remontant. Utilisez un non signé.
la source
size_t est un type de données entier non signé. Sur les systèmes utilisant la bibliothèque GNU C, ce sera int non signé ou entier long non signé. size_t est couramment utilisé pour l'indexation de tableaux et le comptage de boucles.
la source
size_t ou tout type non signé peut être considéré comme une variable de boucle car les variables de boucle sont généralement supérieures ou égales à 0.
Lorsque nous utilisons un objet size_t , nous devons nous assurer que dans tous les contextes où il est utilisé, y compris l'arithmétique, nous ne voulons que des valeurs non négatives. Par exemple, le programme suivant donnerait certainement le résultat inattendu:
la source
size_t
est un type de données entier non signé qui ne peut affecter que 0 et plus de 0 valeurs entières. Il mesure les octets de la taille de n'importe quel objet et est retourné par l'sizeof
opérateur.const
est la représentation syntaxique desize_t
, mais sansconst
vous pouvez exécuter le programme.size_t
régulièrement utilisé pour l'indexation de tableaux et le comptage de boucles. Si le compilateur fonctionne,32-bit
il fonctionneraitunsigned int
. Si le compilateur fonctionne,64-bit
il fonctionneraitunsigned long long int
également. Il existe une taille maximale ensize_t
fonction du type de compilateur.size_t
définir déjà sur le<stdio.h>
fichier d' en- tête, mais il peut également définir par<stddef.h>
,<stdlib.h>
,<string.h>
,<time.h>
, les en-<wchar.h>
têtes.const
)Production -:
size = 800
const
)Production -:
size = 800
la source
D'après ma compréhension,
size_t
est ununsigned
entier dont la taille en bits est suffisamment grande pour contenir un pointeur de l'architecture native.Donc:
la source
size_t
. Plusieurs exemples: les compilateurs C en mode réel x86 peuvent avoir 32 bitsFAR
ouHUGE
pointeurs mais size_t est toujours 16 bits. Autre exemple: Watcom C avait un pointeur spécial pour la mémoire étendue de 48 bits de large, mais cesize_t
n'était pas le cas. Sur le contrôleur intégré avec l'architecture Harvard, vous n'avez pas non plus de corrélation, car les deux concernent des espaces d'adressage différents.size_t