2009-02-02 16 views
111

En varios ejemplos de C++, veo un uso del tipo size_t donde habría usado un int simple. ¿Cuál es la diferencia, y por qué size_t debería ser mejor?¿Cuál es la diferencia entre size_t e int en C++?

+3

Para un ejemplo real donde no son intercambiables, vea una pregunta que hice anteriormente: http://stackoverflow.com/questions/645168/how-to-write-a-stdbitset-template-that-works-on -32-y-64-bit –

Respuesta

119

De the friendly Wikipedia:

El stdlib.h y archivos de cabecera stddef.h definir un tipo de datos llamado size_t que se utiliza 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 tamaño del operador se evalúa como size_t.

El tipo real de size_t depende de la plataforma; un error común es suponer 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 Why size_t matters

+23

Y entonces, ¿qué es size_t? – NDEthos

+2

@NDEthos ¡Depende! En este caso, Linux '/ usr/include/stdlib.h' obtiene la definición de'/usr/lib/gcc/x86_64-redhat-linux/5.3.1/include/stddef.h' y en ella el valor predeterminado es 'long unsigned int' a menos que algún otro archivo de encabezado diga lo contrario. –

+1

Confirmo que [size_t a int tuncation es peligroso] (https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2016-2315). Esto podría estar fuera del 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

5

Es porque size_t puede ser cualquier cosa que no sea int (tal vez una estructura). La idea es que desacopla su trabajo del tipo subyacente.

+6

Creo que size_t está garantizado como un alias para un entero sin signo, por lo que no puede ser una estructura. Sin embargo, no tengo una referencia práctica para respaldar esto ahora. – unwind

+8

@unwind: C99: TC3, 7.17 §2 – Christoph

+1

@danio ¿Por qué es así? ¿Puedes explicarlo? –

22

size_t es el tipo que se utiliza para representar tamaños (como su nombre lo indica). Su plataforma (e incluso su implementación potencial) depende, y debe usarse solo para este propósito. Obviamente, representando un tamaño, size_t no tiene firma. Muchas funciones stdlib, incluyendo malloc, sizeof y varias funciones de operación de cadenas usan size_t como un tipo de datos.

Un int está firmado por defecto, y aunque su tamaño depende también de la plataforma, será un 32bits fijo en la mayoría de las máquinas modernas (aunque size_t es 64 bits en la arquitectura de 64 bits, int permanece 32bits largo en arquitecturas).

En resumen: utilice size_t para representar el tamaño de un objeto y int (o largo) en otros casos.

0

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

pegar aquí la información requerida:

SIZE_T es una ULONG_PTR que representa el número máximo de bytes a la que un puntero puede apuntar.

Este tipo se declara como sigue:

typedef ULONG_PTR SIZE_T; 

Un ULONG_PTR es un tipo largo sin signo utilizado para la precisión del puntero. Se usa al convertir un puntero a un tipo largo para realizar la aritmética del puntero.

Este tipo se declara como sigue:

typedef unsigned __int3264 ULONG_PTR; 
+0

'SIZE_T' no es' size_t', de lo que se preguntó OP. – ikegami

+0

Esa es una extensión de Microsoft, no es parte del lenguaje estándar. – Davislor

1

El tipo size_t se define como el tipo entero sin signo del operador sizeof. 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 un long int también tiene 64 bits, esto se llama convención LP64; si long int es de 32 bits, pero long long int y los punteros son de 64 bits, eso es LLP64.También puede obtener el reverso, un programa que usa instrucciones de 64 bits para la velocidad, pero punteros de 32 bits para ahorrar memoria. Además, int está firmado y size_t no está firmado.

Históricamente existían 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 populares microordenadores 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 producía muchas máquinas que tenían direcciones más amplias que sus registros. De vez en cuando todavía veo preguntas 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 podían soportar 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; había mainframes IBM con direcciones de 15 bits, 24 bits o 31 bits. También sigue viendo diferentes tamaños de ALU y bus de direcciones en los sistemas integrados.

Cada vez es más pequeño que intsize_t, y se intenta almacenar el tamaño o el desplazamiento de un archivo muy grande o un objeto en un unsigned int, existe la posibilidad de que podría desbordarse y causar un error. Con un int, también existe la posibilidad de obtener un número negativo. Si un int o unsigned int es más ancho, el programa se ejecutará correctamente pero desperdiciará la memoria.

En general, debe utilizar el tipo correcto para el propósito si desea la portabilidad. Mucha gente recomendará que uses matemáticas firmadas en lugar de sin firmar (para evitar errores sutiles y desagradables como 1U < -3). Para ese propósito, la biblioteca estándar define ptrdiff_t en <stddef.h> como el tipo firmado del resultado de restar un puntero a otro.

Dicho esto, una solución podría ser la de límites a comprobar todas las direcciones y las compensaciones contra INT_MAX y, o bien 0 o INT_MIN según proceda, y se encienden las advertencias del compilador sobre la comparación de cantidades firmado y sin firmar en caso de que se pierda ninguno. Siempre, siempre, siempre debes verificar tus accesos a la matriz para desbordamiento en C de todos modos.

Cuestiones relacionadas