sizeof es un operador unario en los lenguajes de programación C y C ++ . Se genera el tamaño de almacenamiento de una expresión o un tipo de datos , medida en el número de carbonilla unidades -sized. En consecuencia, se garantiza que el tamaño de construcción de (char) es 1 . El número real de bits de tipo char se especifica mediante la macro del preprocesador CHAR_BIT , definida en el estándar include file limits.h . En la mayoría de las plataformas informáticas modernas, esto es de ocho bits. El resultado de sizeof tiene un tipo de entero sin signo que generalmente se denota porsize_t .
El operador tiene un solo operando, que es una expresión o la conversión de un tipo de datos, que es un tipo de datos entre paréntesis. Los tipos de datos no solo pueden ser tipos primitivos , como enteros y de punto flotante , sino también tipos de puntero y tipos de datos compuestos ( uniones , estructuras y clases de C ++ ).
Propósito
Muchos programas deben conocer el tamaño de almacenamiento de un tipo de datos en particular. Aunque para cualquier implementación dada de C o C ++ el tamaño de un tipo de datos particular es constante, los tamaños de incluso los tipos primitivos en C y C ++ pueden definirse de manera diferente para diferentes plataformas de implementación. Por ejemplo, la asignación en tiempo de ejecución del espacio de la matriz puede usar el siguiente código, en el que el operador sizeof se aplica a la conversión del tipo int :
int * puntero = malloc (10 * tamaño de (int));
En este ejemplo, la función malloc asigna memoria y devuelve un puntero al bloque de memoria. El tamaño del bloque asignado es igual al número de bytes para un solo objeto de tipo int multiplicado por 10, proporcionando espacio para diez enteros.
Por lo general, no es seguro asumir el tamaño de ningún tipo de datos. Por ejemplo, aunque la mayoría de las implementaciones de C y C ++ en sistemas de 32 bits definen el tipo int en cuatro octetos, este tamaño puede cambiar cuando el código se transfiere a un sistema diferente, rompiendo el código. La excepción a esto es el tipo de datos char , que siempre tiene el tamaño 1 en cualquier implementación de C compatible con los estándares. Además, con frecuencia es difícil predecir el tamaño de los tipos de datos compuestos, como una estructura o unión , debido al relleno. El uso de sizeof mejora la legibilidad, ya que evita constantes numéricas sin nombre ( números mágicos ).
Una sintaxis equivalente para asignar el mismo espacio de matriz resulta de usar la forma desreferenciada del puntero a la dirección de almacenamiento, esta vez aplicando el operador a una variable de puntero:
int * puntero = malloc (10 * tamaño de * puntero);
Usar
El operador sizeof produce el espacio de almacenamiento de memoria requerido de su operando cuando se compila el código. El operando se escribe siguiendo la palabra clave sizeof y puede ser el símbolo de un espacio de almacenamiento, por ejemplo, una variable, una expresión o un tipo de conversión. Este último es un nombre de tipo entre paréntesis. El resultado del operador es el tamaño del operando en bytes o el tamaño del requisito de almacenamiento de memoria. Para las expresiones, evalúa el tamaño de representación para el tipo que resultaría de la evaluación de la expresión, que no se realiza.
Por ejemplo, dado que sizeof (char) se define como 1 [1] y asumiendo que el tipo entero tiene cuatro bytes de longitud, se imprime el siguiente fragmento de código1,4:
char c;printf ("% zu,% zu \ n", tamaño de c, tamaño de (int));
Ciertos archivos de encabezado estándar, como stddef.h , definen size_t para denotar el tipo integral sin signo del resultado de una expresión sizeof . El especificador de ancho printf z está destinado a formatear ese tipo.
sizeof no se puede utilizar en expresiones del preprocesador de C , como #if , porque es un elemento del lenguaje de programación, no de la sintaxis del preprocesador, que no tiene tipos de datos.
El siguiente ejemplo en C ++ usa el operador sizeof con plantillas variadic.
plantillastd :: size_t GetSize (Args && ... args){ / * Obtener el tamaño del paquete de parámetros. * / std :: size_t Count = sizeof ... (Args); return Count; }
sizeof se puede usar con plantillas variadas en C ++ 11 y superior en un paquete de parámetros para determinar el número de argumentos.
Aplicación a matrices
Cuando se aplica sizeof al nombre de una matriz, el resultado es el número de bytes necesarios para almacenar toda la matriz. Esta es una de las pocas excepciones a la regla de que el nombre de una matriz se convierte en un puntero al primer elemento de la matriz, y es posible simplemente porque el tamaño real de la matriz es fijo y conocido en el momento de la compilación, cuando el operador sizeof se evalúa. El siguiente programa usa sizeof para determinar el tamaño de una matriz declarada, evitando un desbordamiento del búfer al copiar caracteres:
#include int main (int argc, char ** argv){ tampón de carbón [10]; / * Matriz de 10 caracteres * / / * Copiar como máximo 9 caracteres de argv [1] al búfer, * termina en nulo el búfer. * / snprintf (búfer, tamaño del búfer, "% s", argv [1]); return 0;}
Aquí, sizeof buffer es equivalente a 10 * sizeof buffer [0] , que se evalúa como 10, porque el tamaño del tipo char se define como 1.
C99 agrega soporte para miembros de matriz flexibles a las estructuras. Esta forma de declaración de matriz está permitida como último elemento solo en estructuras, y se diferencia de las matrices normales en que no se especifica la longitud al compilador. Para una estructura llamada s que contiene un miembro de matriz flexible llamado a , sizeof s es, por tanto, equivalente a offsetof (s, a) :
#include struct flexarray { char val; int array []; / * Miembro de matriz flexible; debe ser el último elemento de la estructura * /};int main (int argc, char ** argv){ printf ("tamaño de (estructura flexible matriz) ==% zu \ n", tamaño de (estructura estructura flexible)); return 0;}
En este caso, el operador sizeof devuelve el tamaño de la estructura, incluido cualquier relleno, pero sin ningún almacenamiento permitido para la matriz. La mayoría de las plataformas producen el siguiente resultado:
- sizeof (struct flexarray) == 4
C99 también permite matrices de longitud variable que tienen la longitud especificada en tiempo de ejecución, [2] aunque la característica se considera una implementación opcional en versiones posteriores del estándar C. En tales casos, el operador sizeof se evalúa en parte en tiempo de ejecución para determinar el almacenamiento ocupado por la matriz.
#includetamaño_t tamaño flexible (int n){ char b [n + 3]; / * Matriz de longitud variable * / return sizeof b; / * Tamaño del tiempo de ejecución de * /}int main (vacío){ size_t tamaño = flexsize (10); / * flexsize devuelve 13 * / return 0;}
sizeof se puede utilizar para determinar el número de elementos en una matriz, dividiendo el tamaño de toda la matriz por el tamaño de un solo elemento:
int main (vacío){ int tab [10]; printf ("Número de elementos en la matriz:% zu \ n", tamaño de la pestaña / tamaño de la pestaña [0]); / * rinde 10 * / return 0;}
Tipos incompletos
sizeof sólo se puede aplicar a tipos definidos "completamente". Con matrices, esto significa que las dimensiones de la matriz deben estar presentes en su declaración y que el tipo de los elementos debe estar completamente definido. Para estructuras y uniones , esto significa que debe haber una lista de miembros de tipos completamente definidos. Por ejemplo, considere los siguientes dos archivos fuente:
/ * archivo1.c * /int arr [10];estructura x {int uno; int dos;};/ * más código * // * archivo2.c * /extern int arr [];estructura x;/ * más código * /
Ambos archivos son C perfectamente legales y el código en file1.c puede aplicar sizeof a arr y estructura x . Sin embargo, es ilegal para el código en file2.c para hacer esto, porque las definiciones en file2.c no está completo. En el caso de arr , el código no especifica la dimensión de la matriz; sin esta información, el compilador no tiene forma de saber cuántos elementos hay en la matriz y no puede calcular el tamaño total de la matriz. Asimismo, el compilador no puede calcular el tamaño de struct x porque no sabe de qué miembros está compuesto y, por lo tanto, no puede calcular la suma de los tamaños de los miembros de la estructura (y el relleno). Si el programador proporcionó el tamaño de la matriz en su declaración en file2.c , o completó la definición de struct x proporcionando una lista de miembros, esto permitiría la aplicación de sizeof a arr o struct x en ese archivo fuente.
Miembros de objeto
C ++ 11 introdujo la posibilidad de aplicar el parámetro sizeof a miembros específicos de una clase sin la necesidad de crear una instancia del objeto para lograrlo. [3] El siguiente ejemplo, por ejemplo, produce4 y 8 en la mayoría de las plataformas.
#includestruct foo { int a; int b;};int main (){ std :: cout << tamaño de foo :: a << "\ n" << tamaño de (foo) << "\ n";}
Paquetes de plantillas variadic
C ++ 11 introdujo plantillas variadas ; la palabra clave sizeof seguida de puntos suspensivos devuelve el número de elementos en un paquete de parámetros.
plantillavoid print_size (Args ... args){ std :: cout << tamaño de ... (argumentos) << "\ n";}int main (){ tamaño de impresión (); // salidas 0 print_size ("Es la respuesta", 42, verdadero); // salidas 3}
Implementación
Cuando se aplica a un tipo de datos o variable de longitud fija, las expresiones con el operador sizeof se evalúan durante la compilación del programa; se reemplazan por valores de resultado constantes. El estándar C99 introdujo matrices de longitud variable (VLA), que requerían la evaluación de tales expresiones durante la ejecución del programa. En muchos casos, los detalles de implementación pueden documentarse en un documento de interfaz binaria de aplicación (ABI) para la plataforma, especificando formatos, relleno y alineación para los tipos de datos, a los que el compilador debe ajustarse.
Acolchado de estructura
Al calcular el tamaño de cualquier tipo de objeto, el compilador debe tener en cuenta cualquier alineación de estructura de datos requerida para cumplir con las restricciones de eficiencia o arquitectura. Muchas arquitecturas de computadora no admiten el acceso de varios bytes a partir de una dirección de byte que no sea un múltiplo del tamaño de la palabra, e incluso cuando la arquitectura lo permite, generalmente el procesador puede buscar un objeto alineado con la palabra más rápido de lo que puede buscar un objeto. que abarca varias palabras en la memoria. [4] Por lo tanto, los compiladores generalmente alinean las estructuras de datos con al menos un límite de palabras y también alinean los miembros individuales con sus respectivos límites. En el siguiente ejemplo, es probable que el estudiante de estructura esté alineado en un límite de palabras, que también es donde comienza la calificación del miembro , y es probable que la edad del miembro comience en la siguiente dirección de palabra. El compilador logra lo último insertando bytes de relleno entre los miembros según sea necesario para satisfacer los requisitos de alineación. También puede haber un relleno al final de una estructura para asegurar una alineación adecuada en caso de que la estructura se use como un elemento de una matriz.
Por tanto, el tamaño agregado de una estructura en C puede ser mayor que la suma de los tamaños de sus miembros individuales. Por ejemplo, en muchos sistemas se imprime el siguiente código8:
estudiante de estructura { grado de char; / * char tiene 1 byte de longitud * / int age; / * int tiene 4 bytes de longitud * /};printf ("% zu", sizeof (estructura estudiante));
Ver también
Referencias
- ^ "Estándar C99 (ISO / IEC9899)" (PDF) . ISO / IEC . 7 de septiembre de 2007. 6.5.3.4.3, p. 80 . Consultado el 31 de octubre de 2010 .
- ^ "WG14 / N1124 Comité Borrador ISO / IEC 9899" (PDF) . 6 de mayo de 2005. 6 de mayo de 2005. 6.5.3.4 El tamaño del operador.
- ^ http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2007/n2253.html
- ^ Rentzsch, Jonathan (8 de febrero de 2005). "Alineación de datos: enderece y vuele a la derecha" . www.ibm.com . Consultado el 29 de septiembre de 2014 .