En varios ejemplos de C ++ veo un uso del tipo size_t
donde habría usado un simple int
. ¿Cuál es la diferencia y por qué size_t
debería ser mejor?
En varios ejemplos de C ++ veo un uso del tipo size_t
donde habría usado un simple int
. ¿Cuál es la diferencia y por qué size_t
debería ser mejor?
Respuestas:
Los archivos de encabezado stdlib.h y stddef.h definen un tipo de datos llamado size_t que se usa para representar el tamaño de un objeto. Las funciones de biblioteca que toman tamaños esperan que sean del tipo size_t, y el operador sizeof se evalúa como size_t.
El tipo real de size_t depende de la plataforma; Un error común es asumir que size_t es lo mismo que unsigned int, lo que puede conducir a errores de programación, particularmente a medida que las arquitecturas de 64 bits se vuelven más frecuentes.
Además, verifique por qué size_t importa
/usr/include/stdlib.h
obtiene la definición /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h
y en ella está predeterminada a long unsigned int
menos que algún otro archivo de encabezado indique lo contrario.
size_t es el tipo utilizado para representar tamaños (como su nombre lo indica). Su plataforma (e incluso su implementación potencial) depende y solo debe usarse para este propósito. Obviamente, representando un tamaño, size_t no está firmado. Muchas funciones stdlib, incluidas malloc, sizeof y varias funciones de operación de cadena, usan size_t como tipo de datos.
Un int está firmado de manera predeterminada, y aunque su tamaño también depende de la plataforma, será un fijo de 32 bits en la mayoría de las máquinas modernas (y aunque size_t es de 64 bits en la arquitectura de 64 bits, int tiene 32 bits de largo en esas arquitecturas).
Para resumir: use size_t para representar el tamaño de un objeto e int (o long) en otros casos.
El size_t
tipo se define como el tipo integral sin signo del sizeof
operador. En el mundo real, a menudo verá int
definido como 32 bits (para compatibilidad con versiones anteriores) pero size_t
definido como 64 bits (para que pueda declarar matrices y estructuras de más de 4 GiB de tamaño) en plataformas de 64 bits. Si a long int
también es de 64 bits, esto se llama la convención LP64; si long int
es de 32 bits long long int
y los punteros son de 64 bits, eso es LLP64. También puede obtener el reverso, un programa que utiliza instrucciones de velocidad de 64 bits, pero punteros de 32 bits para ahorrar memoria. Además, int
está firmado y size_t
no está firmado.
Históricamente hubo una serie de otras plataformas donde las direcciones eran más anchas o más cortas que el tamaño nativo de int
. De hecho, en los años 70 y principios de los 80, esto era más común que no: todos los microordenadores populares de 8 bits tenían registros de 8 bits y direcciones de 16 bits, y la transición entre 16 y 32 bits también produjo muchas máquinas que tenía direcciones más anchas que sus registros. Ocasionalmente todavía veo preguntas aquí sobre Borland Turbo C para MS-DOS, cuyo modo de memoria enorme tenía direcciones de 20 bits almacenadas en 32 bits en una CPU de 16 bits (pero que podría admitir el conjunto de instrucciones de 32 bits del 80386); el Motorola 68000 tenía una ALU de 16 bits con registros y direcciones de 32 bits; hubo mainframes de IBM con direcciones de 15 bits, 24 bits o 31 bits. También puede ver diferentes tamaños de ALU y bus de dirección en sistemas integrados.
Cualquier momento int
es menor size_t
e intenta almacenar el tamaño o el desplazamiento de un archivo u objeto muy grande en un archivo unsigned int
, existe la posibilidad de que se desborde y cause un error. Con un int
, también existe la posibilidad de obtener un número negativo. Si an int
o unsigned int
es más ancho, el programa se ejecutará correctamente pero desperdiciará memoria.
En general, debe usar el tipo correcto para el propósito si desea portabilidad. Mucha gente recomendará que use matemáticas firmadas en lugar de sin firmar (para evitar errores desagradables y sutiles 1U < -3
). A tal fin, los define la biblioteca estándar ptrdiff_t
en <stddef.h>
que el tipo de firmado el resultado de restar un puntero de otro.
Dicho esto, una solución alternativa podría ser verificar los límites de todas las direcciones y compensaciones INT_MAX
y, 0
o INT_MIN
según corresponda, y activar las advertencias del compilador sobre la comparación de cantidades firmadas y no firmadas en caso de que pierda alguna. Siempre, siempre, siempre debe verificar el desbordamiento de sus accesos de matriz en C de todos modos.
Es porque size_t puede ser cualquier cosa que no sea un int (tal vez una estructura). La idea es que desacople su trabajo del tipo subyacente.
size_t
se especifica como un tipo entero sin signo . C11 §6.5.3.4 5 "El valor del resultado de ambos operadores ( sizeof
_Alignof
) está definido por la implementación, y su tipo (un tipo entero sin signo) es size_t
".
La definición de SIZE_T
se encuentra en:
https://msdn.microsoft.com/en-us/library/cc441980.aspx y https://msdn.microsoft.com/en-us/library/cc230394.aspx
Pegando aquí la información requerida:
SIZE_T
es una ULONG_PTR
representación del número máximo de bytes a los que puede apuntar un puntero.
Este tipo se declara de la siguiente manera:
typedef ULONG_PTR SIZE_T;
A ULONG_PTR
es un tipo largo sin signo utilizado para la precisión del puntero. Se utiliza cuando se convierte un puntero en un tipo largo para realizar la aritmética del puntero.
Este tipo se declara de la siguiente manera:
typedef unsigned __int3264 ULONG_PTR;
SIZE_T
no es lo size_t
que preguntó el OP.
SIZE_T
es totalmente diferente de size_t
. No puede declarar una variable de tipo SIZE_T
.