Je suis confondu avec size_t
en C. Je sais qu’il est renvoyé par l’opérateur sizeof
. mais qu’est ce que c’est exactement? Est-ce un type de données?
Disons que j’ai une boucle for
:
for(i = 0; i < some_size; i++)
Devrais-je utiliser int i;
ou size_t i;
?
De Wikipedia :
Selon la norme ISO C 1999 (C99),
size_t
est un type entier non signé d’au moins 16 bits (voir sections 7.17 et 7.18.3).
size_t
est un type de données non signé défini par plusieurs normes C / C ++, par exemple la norme C99 ISO / IEC 9899, définie dansstddef.h
. 1 Il peut être importé davantage en incluantstdlib.h
car ce fichier contient en internestddef.h
.Ce type est utilisé pour représenter la taille d’un object. Les fonctions de bibliothèque qui prennent ou retournent des tailles s’attendent à ce qu’elles soient de type ou aient le type de retour
size_t
. En outre, l’opérateur sizeof de l’opérateur basé sur le compilateur le plus fréquemment utilisé devrait avoir une valeur constante compatible avecsize_t
.
En conséquence, size_t
est un type garanti pour contenir tout index de tableau.
size_t
est un type non signé. Donc, il ne peut représenter aucune valeur négative (<0). Vous l'utilisez lorsque vous comptez quelque chose et vous êtes sûr qu'il ne peut pas être négatif. Par exemple, strlen()
renvoie un size_t
car la longueur d’une chaîne doit être au moins égale à 0.
Dans votre exemple, si votre index de boucle doit 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 object size_t
, vous devez vous assurer que, dans tous les contextes utilisés, y compris l’arithmétique, vous voulez des valeurs non négatives. Par exemple, disons que vous avez:
size_t s1 = strlen(str1); size_t s2 = strlen(str2);
et vous voulez trouver la différence des longueurs de str2
et str1
. Tu ne peux pas faire:
int diff = s2 - s1; /* bad */
En effet, la valeur affectée à diff
sera toujours un nombre positif, même lorsque s2 < s1
, car le calcul est effectué avec des types non signés. Dans ce cas, en fonction de votre cas d'utilisation, il peut être préférable d'utiliser int
(ou long long
) pour s1
et s2
.
Certaines fonctions de C / POSIX pourraient / devraient utiliser size_t
, mais pas pour des raisons historiques. Par exemple, le deuxième paramètre à fgets
devrait idéalement être size_t
, mais est int
.
size_t
est un type pouvant 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 dans stddef.h
de ma machine:
typedef unsigned long size_t;
Si vous êtes du type empirique
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Sortie pour Ubuntu 14.04 64 bits GCC 4.8:
typedef long unsigned int size_t;
Notez que stddef.h
est fourni par GCC et non glibc sous src/gcc/ginclude/stddef.h
dans GCC 4.2.
Apparitions intéressantes de C99
malloc
prend size_t
comme argument, il détermine donc la taille maximale pouvant être allouée.
Et comme il est également renvoyé par sizeof
, je pense qu’il limite la taille maximale d’un tableau quelconque.
Voir aussi: La taille maximale d’un tableau dans C
La page de manuel de types.h dit:
size_t doit être un type entier non signé
Comme personne ne l’a encore mentionné, la signification linguistique principale de size_t
est que l’opérateur sizeof
renvoie une valeur de ce type. De même, la principale signification de ptrdiff_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 elles permettent à ces fonctions de fonctionner avec des objects dont la taille dépasse UINT_MAX sur les systèmes où de tels objects peuvent exister, sans forcer les appelants à passer du code supérieur à “unsigned int” suffirait pour tous les objects possibles.
size_t
et int
ne sont pas interchangeables. Par exemple, sur Linux 64 bits, size_t
est de taille 64 bits (ie sizeof(void*)
) mais int
est 32 bits.
Notez également que size_t
n’est pas signé. Si vous avez besoin d’une version signée, il y a ssize_t
sur certaines plates-formes et cela serait plus pertinent pour votre exemple.
En règle générale, je suggère d’utiliser int
pour la plupart des cas généraux et d’utiliser uniquement size_t
/ ssize_t
lorsqu’il y a un besoin spécifique (avec mmap()
par exemple).
En général, si vous commencez à 0 et que vous montez, utilisez toujours un type non signé pour éviter un débordement qui vous amènera dans une situation de valeur négative. Ceci est extrêmement important, car si les limites de votre tableau sont inférieures au maximum de votre boucle, mais que votre boucle maximale est supérieure à la valeur maximale de votre type, vous obtiendrez un résultat 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 allant vers le haut. Utilisez un non signé.
size_t est un type de données entier non signé. Sur les systèmes utilisant la bibliothèque GNU C, ce sera unsigned int ou unsigned long int. size_t est couramment utilisé pour l’indexation de tableaux et le comptage de boucles.
size_t ou n’importe quel type non signé peut être utilisé comme variable de boucle car les variables de boucle sont généralement supérieures ou égales à 0.
Lorsque nous utilisons un object size_t , nous devons nous assurer que dans tous les contextes utilisés, 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:
// C program to demonstrate that size_t or // any unsigned int type should be used // carefully when used in a loop #include int main() { const size_t N = 10; int a[N]; // This is fine for (size_t n = 0; n < N; ++n) a[n] = n; // But reverse cycles are tricky for unsigned // types as can lead to infinite loop for (size_t n = N-1; n >= 0; --n) printf("%d ", a[n]); } Output Infinite loop and then segmentation fault
D’après ce que je comprends, size_t
est un entier unsigned
dont la taille est suffisamment grande pour contenir un pointeur de l’architecture native.
Alors:
sizeof(size_t) >= sizeof(void*)