unsigned int vs. size_t

Observé que el código C y C ++ moderno parece usar size_t lugar de int / unsigned int prácticamente en todas partes, desde los parámetros para las funciones de cadena C hasta el STL. Tengo curiosidad sobre la razón de esto y los beneficios que trae.

El tipo size_t es el tipo entero sin signo que es el resultado del operador sizeof (y del operador offsetof ), por lo que se garantiza que sea lo suficientemente grande como para contener el tamaño del objeto más grande que su sistema puede manejar (por ejemplo, una matriz estática de 8Gb).

El tipo size_t puede ser más grande, igual o más pequeño que un unsigned int , y su comstackdor puede hacer suposiciones al respecto para la optimización.

Puede encontrar información más precisa en el estándar C99, sección 7.17, cuyo borrador está disponible en Internet en formato pdf o en el estándar C11, sección 7.19, también disponible como borrador en formato pdf .

Classic C (el dialecto temprano de C descrito por Brian Kernighan y Dennis Ritchie en The C Programming Language, Prentice-Hall, 1978) no proporcionó size_t . El comité de estándares de C introdujo size_t para eliminar un problema de portabilidad

Explicado en detalle en embedded.com (con un muy buen ejemplo)

En resumen, size_t nunca es negativo y maximiza el rendimiento porque se define como el tipo de entero sin signo que es lo suficientemente grande, pero no demasiado grande, para representar el tamaño del objeto más grande posible en la plataforma de destino.

Los tamaños nunca deben ser negativos, y de hecho size_t es un tipo sin firmar. Además, como size_t no tiene firma, puede almacenar números que son aproximadamente dos veces más grandes que en el tipo firmado correspondiente, porque podemos usar el bit de signo para representar la magnitud, como todos los demás bits en el entero sin signo. Cuando ganamos un bit más, estamos multiplicando el rango de números que podemos representar por un factor de aproximadamente dos.

Entonces, usted pregunta, ¿por qué no simplemente usa una unsigned int ? Puede que no sea capaz de contener números suficientemente grandes. En una implementación donde unsigned int es de 32 bits, el mayor número que puede representar es 4294967295 . Algunos procesadores, como el IP16L32, pueden copiar objetos mayores de 4294967295 bytes.

Entonces, usted pregunta, ¿por qué no usar un unsigned long int ? Exige un costo de rendimiento en algunas plataformas. El estándar C requiere que un long ocupe al menos 32 bits. Una plataforma IP16L32 implementa cada 32 bits de largo como un par de palabras de 16 bits. Casi todos los operadores de 32 bits en estas plataformas requieren dos instrucciones, si no más, porque trabajan con los 32 bits en dos fragmentos de 16 bits. Por ejemplo, mover un largo de 32 bits generalmente requiere dos instrucciones de máquina, una para mover cada fragmento de 16 bits.

Usar size_t evita este peaje de rendimiento. Según este fantástico artículo , “Type size_t es un typedef que es un alias para un tipo de entero sin signo, generalmente unsigned int o unsigned long , pero posiblemente incluso unsigned long long . Se supone que cada implementación de Standard C elige el entero sin signo que sea lo suficientemente grande- -pero no más grande de lo necesario- para representar el tamaño del objeto más grande posible en la plataforma objective “.

El tipo size_t es el tipo devuelto por el operador sizeof. Es un entero sin signo capaz de express el tamaño en bytes de cualquier rango de memoria admitido en la máquina host. Está (típicamente) relacionado con ptrdiff_t en que ptrdiff_t es un valor entero con signo tal que sizeof (ptrdiff_t) y sizeof (size_t) son iguales.

Al escribir el código C siempre debe usar size_t cuando se trata de rangos de memoria.

Por otro lado, el tipo int se define básicamente como el tamaño del valor entero (con signo) que el equipo host puede usar para realizar de manera más eficiente la aritmética de enteros. Por ejemplo, en muchas computadoras de tipo PC más antiguas, el valor sizeof (size_t) sería 4 (bytes) pero sizeof (int) sería 2 (byte). La aritmética de 16 bits fue más rápida que la aritmética de 32 bits, aunque la CPU podría manejar un espacio de memoria (lógico) de hasta 4 GiB.

Utilice el tipo int solo cuando le importe la eficacia, ya que su precisión real depende en gran medida de las opciones del comstackdor y de la architecture de la máquina. En particular, el estándar C especifica las siguientes invariantes: sizeof (char) <= sizeof (short) <= sizeof (int) <= sizeof (long) sin colocar otras limitaciones en la representación real de la precisión disponible para el programador para cada uno de estos tipos primitivos.

Nota: Esto NO es lo mismo que en Java (que realmente especifica la precisión del bit para cada uno de los tipos ‘char’, ‘byte’, ‘short’, ‘int’ y ‘long’).

Escriba size_t debe ser lo suficientemente grande como para almacenar el tamaño de cualquier objeto posible. Unsigned int no tiene que cumplir esa condición.

Por ejemplo, en sistemas de 64 bits, int y unsigned int pueden ser de 32 bits de ancho, pero size_t debe ser lo suficientemente grande como para almacenar números superiores a 4G.

Este extracto del manual de glibc 0.02 también puede ser relevante cuando se investiga el tema:

Existe un problema potencial con el tipo size_t y las versiones de GCC anteriores a la versión 2.4. ANSI C requiere que size_t siempre sea un tipo sin firmar. Para compatibilidad con los archivos de cabecera de los sistemas existentes, GCC define size_t en stddef.h' to be whatever type the system's sys / types.h lo define. La mayoría de los sistemas Unix que definen size_t en `sys / types.h ‘, lo definen como un tipo firmado. Cierto código en la biblioteca depende de que size_t sea un tipo sin firmar, y no funcionará correctamente si está firmado.

El código de la biblioteca GNU C que espera que size_t no esté firmado es correcto. La definición de size_t como un tipo firmado es incorrecta. Planeamos que en la versión 2.4, GCC siempre defina size_t como un tipo sin signo, y el fixincludes' script will massage the system's sys / types.h ‘para no entrar en conflicto con esto.

Mientras tanto, solucionamos este problema al decirle explícitamente a GCC que use un tipo sin signo para size_t al comstackr la biblioteca C de GNU. `configure ‘detectará automáticamente qué tipo de GCC usa para size_t arreglar para anularlo si es necesario.

Si mi comstackdor está configurado en 32 bits, size_t no es más que un typedef para unsigned int . Si mi comstackdor está configurado en 64 bits, size_t no es más que un typedef para unsigned long long .

size_t es el tamaño de un puntero.

Entonces, en 32 bits o el modelo común ILP32 (entero, largo, puntero) size_t es de 32 bits. y en 64 bits o el modelo LP64 (largo, puntero) común size_t es de 64 bits (los enteros son todavía 32 bits).

Hay otros modelos, pero estos son los que usa g ++ (al menos por defecto)