¿Qué es size_t en C?

4 minutos de lectura

avatar de usuario
Vijay

me estoy confundiendo con size_t en C. Sé que es devuelto por el sizeof operador. ¿Pero qué es exactamente? ¿Es un tipo de datos?

digamos que tengo un for círculo:

for(i = 0; i < some_size; i++)

debo usar int i; o size_t i;?

  • Si esas son sus únicas opciones, use int Si some_size está firmado, size_t si no está firmado.

    – Nate

    31 de marzo de 2010 a las 5:59

  • @Nate Eso es incorrecto. POSIX tiene un tipo ssize_t pero el tipo realmente correcto para usar es ptrdiff_t.

    – Molossus Spondee

    19 de marzo de 2017 a las 18:46

  • Las respuestas no son tan claras como en Programación de bajo nivel: C, ensamblaje y ejecución de programas en Intel® 64. Como se indica en el libro, usando un índice int i puede no ser suficiente para abordar una gran variedad. Así que al usar size_t i puede abordar más índices, por lo que incluso si tiene una matriz enorme, eso no debería ser un problema. size_t es un tipo de datos: generalmente un unsigned long int pero esto depende de su sistema.

    –bruno

    14 de febrero de 2020 a las 20:06


avatar de usuario
sblom

De Wikipedia:

Según la norma ISO C de 1999 (C99), size_t es un tipo entero sin signo de al menos 16 bits (consulte las secciones 7.17 y 7.18.3).

size_tes un tipo de datos sin firmar definido por varios estándares C/C++, por ejemplo, el estándar C99 ISO/IEC 9899, ​​que se define en stddef.h.1 Se puede importar aún más mediante la inclusión de
stdlib.h ya que este archivo incluye sub internamente stddef.h.

Este tipo se utiliza para representar el tamaño de un objeto. Las funciones de biblioteca que toman o devuelven tamaños esperan que sean de tipo o tengan el tipo de retorno de size_t. Además, el operador basado en compilador más utilizado, sizeof, debe evaluarse como un valor constante que sea compatible con
size_t.

Como implicación, size_t es un tipo garantizado para contener cualquier índice de matriz.

  • “Las funciones de biblioteca que toman o devuelven tamaños esperan que sean del tipo … size_t” Excepto que stat() usa off_t para el tamaño de un archivo

    – Draemon

    26 mayo 2010 a las 22:12

  • @Draemon Ese comentario refleja una confusión fundamental. size_t es para objetos en la memoria. El estándar C ni siquiera define stat() o off_t (esas son definiciones POSIX) o cualquier cosa que tenga que ver con discos o sistemas de archivos – se detiene en FILE arroyos La administración de la memoria virtual es completamente diferente de los sistemas de archivos y la administración de archivos en lo que respecta a los requisitos de tamaño, por lo que mencionar off_t es irrelevante aquí.

    – jw013

    10 de junio de 2013 a las 19:57


  • @ jw013: Difícilmente lo llamaría una confusión fundamental, pero haces un punto interesante. Aún así, el texto citado no dice “tamaños de objetos en memoria”, y “desplazamiento” no es un buen nombre para un tipo de tamaño, independientemente de dónde esté almacenado.

    – Draemon

    13 de junio de 2013 a las 22:50

  • @Draemon Buen punto. Esta respuesta cita a Wikipedia, que en este caso no tiene la mejor explicación, en mi opinión. El estándar C en sí mismo es mucho más claro: define size_t como el tipo del resultado de la sizeof operador (7.17p2 sobre <stddef.h>). La sección 6.5 explica exactamente cómo funcionan las expresiones C (6.5.3.4 para sizeof). Como no puede aplicar sizeof a un archivo de disco (principalmente porque C ni siquiera define cómo funcionan los discos y los archivos), no hay lugar para la confusión. En otras palabras, culpe a Wikipedia (y esta respuesta por citar a Wikipedia y no al estándar C real).

    – jw013

    13 de junio de 2013 a las 22:57


  • @Draemon: también estaría de acuerdo con la evaluación de “confusión fundamental”. Si no ha leído los estándares de C/C++, podría pensar que “objeto” se refiere a “programación orientada a objetos”, lo cual no es así. Lea el estándar C, que no tiene ninguno de esos objetos OOP, pero aún tiene objetos, y descúbralo. ¡La respuesta puede sorprenderte!

    –Heath Hunnicutt

    29 de octubre de 2013 a las 2:26


avatar de usuario
Alok Singhal

size_t es un tipo sin firmar. Por lo tanto, no puede representar ningún valor negativo (<0). Lo usa cuando está contando algo y está seguro de que no puede ser negativo. Por ejemplo, strlen() devuelve un size_t porque la longitud de una cadena tiene que ser al menos 0.

En su ejemplo, si su índice de bucle va a ser siempre mayor que 0, podría tener sentido usar size_to cualquier otro tipo de datos sin firmar.

Cuando usas un size_t objeto, debe asegurarse de que en todos los contextos en los que se usa, incluida la aritmética, desea valores no negativos. Por ejemplo, digamos que tienes:

size_t s1 = strlen(str1);
size_t s2 = strlen(str2);

y quieres encontrar la diferencia de las longitudes de str2 y str1. Tú no puedes hacer:

int diff = s2 - s1; /* bad */

Esto se debe a que el valor asignado a diff siempre va a ser un número positivo, incluso cuando s2 < s1, porque el cálculo se realiza con tipos sin firmar. En este caso, dependiendo de cuál sea su caso de uso, es mejor que use int (o long long) por s1 y s2.

Hay algunas funciones en C/POSIX que podrían/deberían usar size_t, pero no por razones históricas. Por ejemplo, el segundo parámetro a fgets idealmente debería ser size_tpero es int.

  • @Alok: dos preguntas: 1) ¿cuál es el tamaño de size_t? 2) por qué debería preferir size_t sobre algo como unsigned int?

    – Lazer

    8 de junio de 2010 a las 18:41


  • @Lazer: el tamaño de size_t es sizeof(size_t). El estándar C garantiza que SIZE_MAX será al menos 65535. size_t es el tipo devuelto por sizeof operador, y se utiliza en la biblioteca estándar (por ejemplo strlen devoluciones size_t). Como dijo Brendan, size_t no tiene por qué ser lo mismo que unsigned int.

    – Alok Singhal

    9 de junio de 2010 a las 5:56

  • @Lazer – sí, size_t se garantiza que es un tipo sin firmar.

    – Alok Singhal

    13 de junio de 2010 a las 14:37

  • Tenga en cuenta que en Linux de 64 bits, int siempre es de 32 bits, pero size_t es de 64 bits. Entonces size_t e int NO son intercambiables.

    – dtoux

    30 de octubre de 2013 a las 2:41

  • @JasonOster, el complemento a dos no es un requisito en el estándar C. Si el valor de s2 - s1 desborda un intel comportamiento no está definido.

    – Alok Singhal

    6 de julio de 2015 a las 0:29

avatar de usuario
Arjun Sreedharan

size_t es un tipo que puede contener cualquier índice de matriz.

Dependiendo de la implementación, puede ser cualquiera de:

unsigned char

unsigned short

unsigned int

unsigned long

unsigned long long

Así es cómo size_t se define en stddef.h de mi maquina:

typedef unsigned long size_t;

  • @chux: De hecho, solo porque una implementación lo defina como tal no significa que todos lo hagan. Caso en cuestión: Windows de 64 bits. unsigned long es de 32 bits, size_t es de 64 bits.

    – Tim Cas

    28 de diciembre de 2014 a las 21:40

  • ¿Es cierto que size_t ¿Es siempre 32 bits en una máquina de 32 bits, 64 bits igualmente?

    – Juan Wu

    24 de agosto de 2016 a las 7:09

  • “Según el estándar ISO C de 1999 (C99), size_t es un tipo de entero sin signo de al menos 16 bits (consulte las secciones 7.17 y 7.18.3)”. Entonces no puede ser un unsigned char?

    – jamesfisher

    29 noviembre 2016 a las 22:35

  • @jameshfisher No estoy seguro de que la restricción de 16 bits sea cierta. uint_least16_t es lo que es al menos 16 bits. Acerca de, size_tel estándar dice “tipo integral sin signo del resultado del operador sizeof” y “El operador sizeof produce el tamaño (en bytes) de su operando”.

    – Arjun Sreedharan

    30 de noviembre de 2016 a las 5:51

  • @jameshfisher quien dice unsigned char no puede ser de 16 bits?!

    – Antti Haapala — Слава Україні

    16 de octubre de 2017 a las 7:52

avatar de usuario
Davislor

Para entrar en por qué size_t necesario para existir y cómo llegamos aquí:

En términos pragmáticos, size_t y ptrdiff_t se garantiza que tengan 64 bits de ancho en una implementación de 64 bits, 32 bits de ancho en una implementación de 32 bits, y así sucesivamente. No podían forzar ningún tipo existente para que significara eso, en cada compilador, sin romper el código heredado.

UN size_t o ptrdiff_t no es necesariamente lo mismo que un intptr_t o uintptr_t. Eran diferentes en ciertas arquitecturas que todavía estaban en uso cuando size_t y ptrdiff_t se agregaron al estándar a fines de la década de 1980 y se volvieron obsoletos cuando C99 agregó muchos tipos nuevos pero aún no se han ido (como Windows de 16 bits). El x86 en modo protegido de 16 bits tenía una memoria segmentada donde la matriz o estructura más grande posible podía tener solo 65 536 bytes de tamaño, pero un far el puntero debía tener 32 bits de ancho, más ancho que los registros. Sobre estos, intptr_t habría sido de 32 bits de ancho, pero size_t y ptrdiff_t podría tener 16 bits de ancho y caber en un registro. ¿Y quién sabía qué tipo de sistema operativo podría escribirse en el futuro? En teoría, la arquitectura i386 ofrece un modelo de segmentación de 32 bits con punteros de 48 bits que ningún sistema operativo ha utilizado nunca.

El tipo de un desplazamiento de memoria no pudo ser long porque demasiado código heredado asume que long tiene exactamente 32 bits de ancho. Esta suposición incluso se incorporó en las API de UNIX y Windows. Desafortunadamente, muchos otros códigos heredados también asumieron que un long es lo suficientemente ancho para contener un puntero, un desplazamiento de archivo, la cantidad de segundos que han transcurrido desde 1970, etc. POSIX ahora proporciona una forma estandarizada de forzar que la última suposición sea cierta en lugar de la primera, pero tampoco es una suposición portátil.

no puede ser int porque solo un pequeño puñado de compiladores en los años 90 hizo int 64 bits de ancho. Entonces realmente se pusieron raros al mantener long 32 bits de ancho. La siguiente revisión de la Norma la declaró ilegal para int ser más ancho que longpero int todavía tiene 32 bits de ancho en la mayoría de los sistemas de 64 bits.

no puede ser long long intque de todos modos se agregó más tarde, ya que se creó para tener al menos 64 bits de ancho incluso en sistemas de 32 bits.

Entonces, se necesitaba un nuevo tipo. Incluso si no lo fuera, todos esos otros tipos significaban algo más que un desplazamiento dentro de una matriz u objeto. Y si hubo una lección del fiasco de la migración de 32 a 64 bits, fue ser específico sobre qué propiedades debe tener un tipo, y no usar uno que significa cosas diferentes en diferentes programas.

avatar de usuario
dtoux

size_t y int no son intercambiables. Por ejemplo, en Linux de 64 bits size_t tiene un tamaño de 64 bits (es decir, sizeof(void*)) pero int es de 32 bits.

También tenga en cuenta que size_t está sin firmar. Si necesita una versión firmada, entonces hay ssize_t en algunas plataformas y sería más relevante para su ejemplo.

Como regla general, sugeriría usar int para la mayoría de los casos generales y solo use size_t/ssize_t cuando hay una necesidad específica para ello (con mmap() por ejemplo).

avatar de usuario
Comunidad

Si eres del tipo empírico,

echo | gcc -E -xc -include 'stddef.h' - | grep size_t

Salida para Ubuntu 14.04 GCC 4.8 de 64 bits:

typedef long unsigned int size_t;

Tenga en cuenta que stddef.h es proporcionado por GCC y no por glibc bajo src/gcc/ginclude/stddef.h en CCG 4.2.

Interesantes apariciones del C99

  • malloc acepta size_t como argumento, por lo que determina el tamaño máximo que se puede asignar.

    Y como también es devuelto por sizeofcreo que limita el tamaño máximo de cualquier matriz.

    Ver también: ¿Cuál es el tamaño máximo de una matriz en C?

avatar de usuario
coadicto

La página de manual para tipos.h dice:

size_t debe ser un tipo entero sin signo

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad