Respuestas:
El size_t
tipo es el tipo entero sin signo que es el resultado del sizeof
operador (y el offsetof
operador), por lo que se garantiza que es 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 8 Gb).
El size_t
tipo puede ser mayor, igual o menor que an unsigned int
, y su compilador 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 pdf .
size_t
puede representar! Si no es así, ¿quién lo hace?
El clásico 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 C presentó 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 está diseñado para ser el tipo 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 signo. Además, debido a size_t
que no tiene signo, puede almacenar números que son aproximadamente dos veces más grandes que en el tipo con signo 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 solo usar un unsigned int
? Es posible que no pueda contener números lo suficientemente grandes. En una implementación donde unsigned int
hay 32 bits, el mayor número que puede representar es 4294967295
. Algunos procesadores, como el IP16L32, pueden copiar objetos más grandes que 4294967295
bytes.
Entonces, preguntas, ¿por qué no usar un unsigned long int
? Exige un peaje de rendimiento en algunas plataformas. El estándar C requiere que una long
ocupe al menos 32 bits. Una plataforma IP16L32 implementa cada una de 32 bits 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 una longitud de 32 bits generalmente requiere dos instrucciones de la máquina: una para mover cada fragmento de 16 bits.
El uso size_t
evita este costo de rendimiento. De acuerdo con este fantástico artículo , "Tipo size_t
es un typedef que es un alias para algún tipo de entero sin signo, típicamente 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 es 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 de destino ".
unsigned int
lata y varía de un sistema a otro. Se requiere que sea al menos 65536
, pero es común 4294967295
y podría ser 18446744073709551615
(2 ** 64-1) en algunos sistemas.
unsigned char
). El estándar no parece contener la cadena '65535' o '65536' en ninguna parte, y '+32767' solo aparece (1.9: 9) en una nota como el mayor entero posible representable en int
; ¡ni siquiera se ofrece garantía que INT_MAX
no pueda ser más pequeña que eso!
El tipo size_t es el tipo devuelto por el operador sizeof. Es un entero sin signo capaz de expresar 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 código C, siempre debe usar size_t cuando se trate de rangos de memoria.
El tipo int, por otro lado, se define básicamente como el tamaño del valor entero (con signo) que la máquina host puede usar para realizar la aritmética de enteros de manera más eficiente. Por ejemplo, en muchas computadoras antiguas tipo PC, el valor sizeof (size_t) sería 4 (bytes) pero sizeof (int) sería 2 (byte). La aritmética de 16 bits era más rápida que la aritmética de 32 bits, aunque la CPU podía manejar un espacio de memoria (lógico) de hasta 4 GiB.
Utilice el tipo int solo cuando le interese la eficiencia, ya que su precisión real depende en gran medida de las opciones del compilador y de la arquitectura de la máquina. En particular, el estándar C especifica los 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 en realidad especifica la precisión de bits para cada uno de los tipos 'char', 'byte', 'short', 'int' y 'long').
size_t
es capaz de representar el tamaño de cualquier objeto individual (por ejemplo: número, matriz, estructura). Todo el rango de memoria puede excedersize_t
size_t
- Espero que no te refieras a eso. La mayoría de las veces no tratamos con matrices donde la cardinalidad del espacio de direcciones + portabilidad incluso importa. En estos casos lo tomarías size_t
. En todos los demás casos, se toman índices de enteros (firmados). Debido a que la confusión (que viene sin previo aviso) que surge del comportamiento de flujo subyacente insospechado de los no firmados es más común y peor que los problemas de portabilidad que pueden surgir en los otros casos.
Escriba size_t debe ser lo suficientemente grande como para almacenar el tamaño de cualquier objeto posible. Unsigned int no tiene que satisfacer esa condición.
Por ejemplo, en sistemas de 64 bits, int y unsigned int pueden tener 32 bits de ancho, pero size_t debe ser lo suficientemente grande como para almacenar números mayores que 4G
size_t
que solo tendría que ser tan grande si el compilador pudiera aceptar un tipo X tal que sizeof (X) arrojaría un valor mayor que 4G. La mayoría de los compiladores rechazarían typedef unsigned char foo[1000000000000LL][1000000000000LL]
, por ejemplo , e incluso foo[65536][65536];
podrían ser legítimamente rechazados si excede un límite documentado definido por la implementación.
Este extracto del manual glibc 0.02 también puede ser relevante al investigar 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 signo. Para compatibilidad con los archivos de encabezado de los sistemas existentes, GCC define size_t en stddef.h' to be whatever type the system's
sys / types.h 'define que es. La mayoría de los sistemas Unix que definen size_t en `sys / types.h ', lo definen como un tipo con signo. Algún código en la biblioteca depende de que size_t sea un tipo sin signo 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 tipo con signo es incorrecta. Planeamos que en la versión 2.4, GCC siempre definirá size_t como un tipo sin signo, y fixincludes' script will massage the system's
sys / types.h 'para no entrar en conflicto con esto.
Mientras tanto, solucionamos este problema diciéndole a GCC explícitamente que use un tipo sin signo para size_t al compilar la biblioteca GNU C. `configure 'detectará automáticamente qué tipo de GCC usa para size_t organizar para anularlo si es necesario.
Si mi compilador está configurado en 32 bits, size_t
no es más que un typedef para unsigned int
. Si mi compilador está configurado en 64 bits, size_t
no es más que un typedef para unsigned long long
.
unsigned long
para ambos casos en algunos sistemas operativos.
size_t es el tamaño de un puntero.
Entonces, en 32 bits o el modelo ILP32 común (entero, largo, puntero) size_t es de 32 bits. y en 64 bits o el modelo LP64 común (largo, puntero) size_t es de 64 bits (los enteros siguen siendo de 32 bits).
Hay otros modelos, pero estos son los que usa g ++ (al menos por defecto)
size_t
no es necesariamente del mismo tamaño que un puntero, aunque comúnmente lo es. Un puntero debe poder apuntar a cualquier ubicación en la memoria; size_t
solo tiene que ser lo suficientemente grande como para representar el tamaño del objeto individual más grande.