¿Cuál es la diferencia entre size_t e int en C ++?

173

En varios ejemplos de C ++ veo un uso del tipo size_tdonde habría usado un simple int. ¿Cuál es la diferencia y por qué size_tdebería ser mejor?

Tunnuz
fuente
3
Para ver un ejemplo real donde no son intercambiables, vea una pregunta que hice anteriormente: stackoverflow.com/questions/645168/…
Tyler McHenry

Respuestas:

153

De la amigable Wikipedia :

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

Joao da Silva
fuente
76
Y entonces, ¿qué es size_t?
NDEthos
8
@NDEthos ¡Depende! En este caso, Linux /usr/include/stdlib.hobtiene la definición /usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.hy en ella está predeterminada a long unsigned intmenos que algún otro archivo de encabezado indique lo contrario.
David Tonhofer
1
Confirmo que size_t para int tuncation es peligroso . Esto podría estar fuera de tema, pero ¿cómo escribir un parche solo para corregir ese tipo de errores cuando ocurre miles de veces en el kernel de Linux?
user2284570
36

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.

Axelle Ziegler
fuente
12

El size_ttipo se define como el tipo integral sin signo del sizeofoperador. En el mundo real, a menudo verá intdefinido como 32 bits (para compatibilidad con versiones anteriores) pero size_tdefinido 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 inttambién es de 64 bits, esto se llama la convención LP64; si long intes de 32 bits long long inty 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, intestá firmado y size_tno 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 intes menor size_te 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 into unsigned intes 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_ten <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_MAXy, 0o INT_MINsegú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.

Davislor
fuente
8

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.

graham.reeds
fuente
8
Creo que size_t en realidad está garantizado como un alias para un entero sin signo, por lo que no puede ser una estructura. Sin embargo, no tengo una referencia útil para respaldar esto en este momento.
relajarse
9
@unwind: C99: TC3, 7.17 §2
Christoph
1
@danio ¿Por qué es así? ¿Puedes explicarlo?
Buitre de Rüppell
2
¡No me vincularía a cplusplus si fuera tú! Si no puede citar capítulos, versos, párrafos y líneas, ¡todo es solo un rumor! :-)
graham.reeds
1
size_tse 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".
chux - Restablecer Monica
-1

La definición de SIZE_Tse 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_Tes una ULONG_PTRrepresentació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_PTRes 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;
Sundar
fuente
2
SIZE_Tno es lo size_tque preguntó el OP.
ikegami
2
Esa es una extensión de Microsoft, no parte del lenguaje estándar.
Davislor
SIZE_Tes totalmente diferente de size_t. No puede declarar una variable de tipo SIZE_T.
calocedrus