Qu'est-ce que la taille t en C?
je me confonds avec size_t
en C. Je sais qu'il est retourné par l'opérateur sizeof
. Mais qu'en est-il exactement? Est-il un type de données?
disons que j'ai une boucle for
:
for(i = 0; i < some_size; i++)
dois-je utiliser int i;
ou size_t i;
?
11 réponses
selon la norme ISO C de 1999 (C99),
size_t
est un entier non signé type 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, qui est défini dansstddef.h
. 1 , Il peut être importés par inclusion destdlib.h
comme ce fichier interne sous comprendstddef.h
.ce type est utilisé pour représenter de la taille d'un objet. Les fonctions de la bibliothèque que les tailles de prise ou de retour s'attendent à eux pour être de type ou de retour de type de
size_t
. En outre, la plupart des compilateur fréquemment utilisé taille de l'opérateur devrait évaluer à un valeur constante compatible avecsize_t
.
comme une implication, size_t
est un type garanti pour contenir n'importe quel indice de tableau.
size_t
est un type non signé. Il ne peut donc pas représenter de valeurs négatives(<0). Vous l'utilisez quand vous comptez quelque chose, et vous êtes sûr qu'il ne peut pas être négatif. Par exemple:, strlen()
renvoie un size_t
parce que la longueur d'une chaîne doit être au moins 0.
dans votre exemple, si votre indice de boucle est toujours supérieur à 0, Il pourrait être logique 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, il est utilisé, y compris l'arithmétique, vous voulez 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
. Vous ne pouvez pas faire:
int diff = s2 - s1; /* bad */
C'est parce que la valeur attribuée à diff
est toujours un nombre positif, même quand s2 < s1
, parce que le calcul est fait avec des types non signés. Dans ce cas, selon le cas d'utilisation, il est préférable d'utiliser int
(ou long long
) pour s1
et s2
.
il y a certaines fonctions dans C/POSIX qui pourraient/devraient utiliser size_t
, mais ne le font pas pour des raisons historiques. Par exemple , le second paramètre de fgets
devrait idéalement être size_t
, mais est int
.
size_t
est un type qui peut contenir n'importe quel index de tableau.
selon la mise en œuvre, 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 le type empirique
echo | gcc -E -xc -include 'stddef.h' - | grep size_t
Sortie Pour Ubuntu 14.04 64-bit GCC 4.8:
typedef long unsigned int size_t;
noter que stddef.h
est fourni par GCC et non glibc sous src/gcc/ginclude/stddef.h
dans GCC 4.2.
Intéressant C99 apparences
-
malloc
prendsize_t
comme argument, donc il détermine le maximum taille pouvant être attribuée.et puisqu'il est aussi retourné par
sizeof
, je pense qu'il limite la taille maximale d'un tableau.Voir aussi: la taille maximale d'un réseau en C
puisque personne ne l'a encore mentionné, la principale signification linguistique de size_t
est que l'opérateur sizeof
renvoie une valeur de ce type. De même, la signification principale de ptrdiff_t
est que soustraire un pointeur d'un autre donnera une valeur de ce type. Les fonctions de bibliothèque qui l'acceptent le font parce qu'elles permettront à ces fonctions de fonctionner avec des objets dont la taille dépasse UINT_MAX sur des systèmes où de tels objets pourraient exister, sans forcer les appelants à code de déchets passant une valeur plus grande que "int non signé" sur les systèmes où le type plus grand suffirait pour tous les objets possibles.
size_t
et int
ne sont pas interchangeables. Par exemple, sur Linux 64 bits size_t
est de taille 64 bits (i.e. sizeof(void*)
) mais int
est de 32 bits.
notez Également que size_t
n'est pas signé. Si vous avez besoin de la version signée, alors il y a ssize_t
sur certaines plateformes et ce 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 seulement l'utilisation 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 allez vers le haut, toujours utiliser un type non signé pour éviter un débordement vous menant dans une situation de valeur négative. Ceci est d'une importance critique, parce que si les limites de votre tableau sont inférieures au max de votre boucle, mais que le max de votre boucle est supérieur au max de votre type, vous allez vous enrouler autour du négatif et vous pouvez éprouver une faille de segmentation 151920920 "(SIGSEGV). Donc, en général, Ne jamais utiliser int pour une boucle commençant à 0 et 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, ceci sera non signé int ou non signé long int. size_t est couramment utilisé pour l'indexation de tableaux et le comptage de boucles.
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:
// C program to demonstrate that size_t or
// any unsigned int type should be used
// carefully when used in a loop
#include<stdio.h>
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 j'ai compris, size_t
est un entier unsigned
dont la taille de bits est assez grande pour contenir un pointeur de l'architecture native.
:
sizeof(size_t) >= sizeof(void*)