¿Qué es size_t en C?

Estoy confundido con size_t en C. Sé que el operador sizeof devuelve. ¿Pero qué es exactamente? ¿Es un tipo de datos?

Digamos que tengo un bucle for :

 for(i = 0; i < some_size; i++) 

Debería usar int i; o size_t i; ?

De la Wikipedia :

De acuerdo con el estándar ISO C de 1999 (C99), size_t es un tipo de entero sin signo de al menos 16 bits (véanse las secciones 7.17 y 7.18.3).

size_t es un tipo de datos sin signo definido por varios estándares de C / C ++, por ejemplo, el estándar C99 ISO / IEC 9899, ​​que se define en stddef.h . 1 Se puede importar aún más mediante la inclusión de stdlib.h ya que este archivo interno incluye stddef.h .

Este tipo se usa para representar el tamaño de un objeto. Las funciones de biblioteca que toman o devuelven tamaños esperan que sean del tipo o que tengan el tipo de devolución de size_t . Además, el tamaño de operador basado en el comstackdor utilizado con más frecuencia debería evaluarse a un valor constante que sea compatible con size_t .

Como una consecuencia, size_t es un tipo garantizado para contener cualquier índice de matriz.

size_t es un tipo sin signo. Por lo tanto, no puede representar ningún valor negativo (<0). Lo usa cuando está contando algo, y está seguro de que no puede ser negativo. Por ejemplo, strlen() devuelve un size_t porque la longitud de una cadena tiene que ser al menos 0.

En su ejemplo, si su índice de bucle va a ser siempre mayor que 0, podría tener sentido utilizar size_t o cualquier otro tipo de datos sin signo.

Cuando utiliza un objeto size_t , debe asegurarse de que en todos los contextos en que se usa, incluida la aritmética, desee valores no negativos. Por ejemplo, digamos que tienes:

 size_t s1 = strlen(str1); size_t s2 = strlen(str2); 

y desea encontrar la diferencia de las longitudes de str2 y str1 . Tú no puedes hacer:

 int diff = s2 - s1; /* bad */ 

Esto se debe a que el valor asignado a diff siempre será un número positivo, incluso cuando s2 < s1 , porque el cálculo se realiza con tipos sin signo. En este caso, dependiendo de cuál sea su caso de uso, es mejor que utilice int (o long long ) para s1 y s2 .

Hay algunas funciones en C / POSIX que podrían / ​​deberían usar size_t , pero no por razones históricas. Por ejemplo, el segundo parámetro para fgets debería ser idealmente size_t , pero es int .

size_t es un tipo que puede contener cualquier índice de matriz.

Dependiendo de la implementación, puede ser cualquiera de:

unsigned char

unsigned short

unsigned int

unsigned long

unsigned long long

Así es como size_t se define en stddef.h de mi máquina:

 typedef unsigned long size_t; 

Si eres del tipo empírico

 echo | gcc -E -xc -include 'stddef.h' - | grep size_t 

Salida para Ubuntu 14.04 64-bit GCC 4.8:

 typedef long unsigned int size_t; 

Tenga en cuenta que stddef.h es proporcionado por GCC y no glibc en src/gcc/ginclude/stddef.h en GCC 4.2.

Interesantes apariciones de C99

  • malloc toma size_t como argumento, por lo que determina el tamaño máximo que puede asignarse.

    Y dado que también es devuelto por sizeof , creo que limita el tamaño máximo de cualquier matriz.

    Ver también: el tamaño máximo de una matriz en C

La página de manual de types.h dice:

size_t será un tipo entero sin signo

Como nadie lo ha mencionado aún, la importancia lingüística principal de size_t es que el operador sizeof devuelve un valor de ese tipo. Del mismo modo, la importancia principal de ptrdiff_t es que restar un puntero a otro arrojará un valor de ese tipo. Las funciones de biblioteca que lo aceptan lo hacen porque permitirá que tales funciones funcionen con objetos cuyo tamaño exceda UINT_MAX en sistemas donde tales objetos podrían existir, sin forzar a los llamantes a perder código pasando un valor mayor que “unsigned int” en sistemas donde el tipo más grande sería suficiente para todos los objetos posibles.

size_t y int no son intercambiables. Por ejemplo, en Linux de 64 bits size_t tiene un tamaño de 64 bits (es decir, sizeof(void*) ) pero int es de 32 bits.

También tenga en cuenta que size_t no tiene firma. Si necesita una versión firmada, entonces hay ssize_t en algunas plataformas y sería más relevante para su ejemplo.

Como regla general, sugeriría usar int para la mayoría de los casos generales y solo usar size_t / ssize_t cuando hay una necesidad específica (con mmap() por ejemplo).

En general, si comienza en 0 y va hacia arriba, siempre use un tipo sin signo para evitar un desbordamiento que lo lleve a una situación de valor negativo. Esto es críticamente importante, porque si los límites de su matriz resultan ser menores que el máximo de su ciclo, pero su máximo de bucle es mayor que el máximo de su tipo, se ajustará negativo y puede experimentar un error de segmentación (SIGSEGV) ) Por lo tanto, en general, nunca use int para un bucle comenzando en 0 y yendo hacia arriba. Use un unsigned.

size_t es un tipo de datos entero sin signo. En los sistemas que usan la Biblioteca C de GNU, esto será unsigned int o unsigned long int. size_t se usa comúnmente para la indexación de matrices y el conteo de bucles.

size_t o cualquier tipo sin signo se puede ver utilizado como variable de bucle ya que las variables de bucle suelen ser mayores o iguales a 0.

Cuando usamos un objeto size_t , tenemos que asegurarnos de que en todos los contextos en que se usa, incluida la aritmética, solo queremos valores no negativos. Por ejemplo, el siguiente progtwig definitivamente daría el resultado inesperado:

 // 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 

Desde mi entendimiento, size_t es un entero unsigned signo cuyo tamaño de bit es lo suficientemente grande como para contener un puntero de la architecture nativa.

Asi que:

 sizeof(size_t) >= sizeof(void*)