sintaxis array c sizeof

c - array - sizeof string



En C, el operador sizeof devuelve 8 bytes cuando pasa 2.5m pero 4 bytes cuando pasa 1.25m*2 (8)

El borrador C11 está aquí: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf . Puede encontrar el borrador de Cx0 aquí: http://c0x.coding-guidelines.com/6.5.3.4.html

En ambos casos, la sección 6.5.3.4 es lo que estás buscando. Básicamente, tu problema se reduce a esto:

// Example 1: long long x = 2500000000; int size = sizeof(x); // returns 8 // Example 2: int x = 1250000000; int y = 2; int size = sizeof(x * y); // returns 4

En el ejemplo 1, tiene una long long (8 bytes), por lo que devuelve 8. En el ejemplo 2, tiene un int * int que devuelve un int , que es de 4 bytes (por lo que devuelve 4).

Para responder a su pregunta de recompensa: Sí y no. sizeof no calculará el tamaño necesario para la operación que intenta realizar, pero le indicará el tamaño de los resultados si realiza la operación con las etiquetas adecuadas:

long long x = 1250000000; int y = 2; int size = sizeof(x * y); // returns 8 // Alternatively int size = sizeof(1250000000LL * 2); // returns 8

Tienes que decir que estás tratando con un número grande o asumirá que está tratando con el tipo más pequeño que puede (que en este caso es int ).

No entiendo por qué el operador sizeof está produciendo los siguientes resultados:

sizeof( 2500000000 ) // => 8 (8 bytes).

... devuelve 8, y cuando hago lo siguiente:

sizeof( 1250000000 * 2 ) // => 4 (4 bytes).

... devuelve 4, en lugar de 8 (que es lo que esperaba). ¿Alguien puede aclarar cómo sizeof determina el tamaño de una expresión (o tipo de datos) y por qué en mi caso específico esto está ocurriendo?

Mi mejor suposición es que el operador sizeof es un operador en tiempo de compilación.

Bounty Question: ¿Hay un operador de tiempo de ejecución que pueda evaluar estas expresiones y producir mi salida esperada (sin conversión)?


La respuesta más simple en una línea es:

sizeof () es una función evaluada en COMPILAR TIEMPO cuya entrada es de tipo CA, cuyo valor se ignora por completo

MÁS DETALLE: ..por lo tanto, como se compila 2500000000, tendría que almacenarse por mucho tiempo, ya que es demasiado largo para caber en un int, por lo tanto este argumento simplemente se compila como ''(tipo) largo''. Sin embargo, 1250000000 y 2 caben en el tipo ''int'', por lo tanto, ese es el tipo pasado a sizeof, ya que el valor resultante nunca se almacena porque el compilador simplemente está interesado en el tipo, la multiplicación nunca se evalúa.


Luchian ya respondió. Solo para completarlo ...

C11 Los estados estándar (el estándar de C ++ tiene líneas similares) que el tipo de un entero literal sin sufijo para designar el tipo se determina de la siguiente manera:

A partir de 6.4.4 Constantes ( borrador C11 ):

Semántica

4 El valor de una constante decimal se calcula base 10; el de una constante octal, base 8; el de una constante hexadecimal, base 16. El primer dígito léxico es el más significativo.

5 El tipo de una constante entera es la primera de la lista correspondiente en la que se puede representar su valor.

Y la tabla es la siguiente:

Constante decimal

int int long int long long int

Constante octal o hexadecimal

int unsigned int long int unsigned long int long long int unsigned long long int

Para las constantes Octal y Hexadecimal, incluso los tipos sin signo son posibles. Entonces, dependiendo de su plataforma, cualquiera que sea en la lista anterior ( int o long int o long long int ) encaja primero (en el orden) será el tipo de entero literal.


Otra forma de poner la respuesta es decir que lo que es relevante para sizeof no es el valor de la expresión sino su tipo. sizeof devuelve el tamaño de memoria para un tipo que se puede proporcionar explícitamente como un tipo o como una expresión. En este caso, el compilador calculará este tipo en tiempo de compilación sin calcular realmente la expresión (siguiendo las reglas conocidas, por ejemplo, si llama a una función, el tipo resultante es el tipo del valor devuelto).

Como otro cartel indicó que hay una excepción para la matriz de longitud variable (cuyo tamaño de tipo solo se conoce en tiempo de ejecución).

En otras palabras, usualmente escribes cosas como sizeof(type) o sizeof expression donde expression es un L-Value. La expresión casi nunca es una informática compleja (como el estúpido ejemplo de llamar a una función anterior): de todos modos sería inútil ya que no se evalúa.

#include <stdio.h> int main(){ struct Stype { int a; } svar; printf("size=%d/n", sizeof(struct Stype)); printf("size=%d/n", sizeof svar); printf("size=%d/n", sizeof svar.a); printf("size=%d/n", sizeof(int));

}

También tenga en cuenta que como sizeof es una palabra clave de idioma, no es necesario un paréntesis de función antes de la expresión final (tenemos el mismo tipo de regla para la palabra clave return).


Para su pregunta de seguimiento, no hay un "operador", y no hay diferencia entre el tamaño de "tiempo de compilación" de una expresión y el tamaño de "tiempo de ejecución".

Si desea saber si un tipo determinado puede contener el resultado que está buscando, siempre puede intentar algo como esto:

#include <stdio.h> #include <limits.h> int main(void) { int a = 1250000000; int b = 2; if ( (INT_MAX / (double) b) > a ) { printf("int is big enough for %d * %d/n", a, b); } else { printf("int is not big enough for %d * %d/n", a, b); } if ( (LONG_MAX / (double) b) > a ) { printf("long is big enough for %d * %d/n", a, b); } else { printf("long is not big enough for %d * %d/n", a, b); } return 0; }

y una solución (un poco) más general, solo para alondras:

#include <stdlib.h> #include <stdio.h> #include <limits.h> /* ''gssim'' is ''get size of signed integral multiplication */ size_t gssim(long long a, long long b); int same_sign(long long a, long long b); int main(void) { printf("size required for 127 * 1 is %zu/n", gssim(127, 1)); printf("size required for 128 * 1 is %zu/n", gssim(128, 1)); printf("size required for 129 * 1 is %zu/n", gssim(129, 1)); printf("size required for 127 * -1 is %zu/n", gssim(127, -1)); printf("size required for 128 * -1 is %zu/n", gssim(128, -1)); printf("size required for 129 * -1 is %zu/n", gssim(129, -1)); printf("size required for 32766 * 1 is %zu/n", gssim(32766, 1)); printf("size required for 32767 * 1 is %zu/n", gssim(32767, 1)); printf("size required for 32768 * 1 is %zu/n", gssim(32768, 1)); printf("size required for -32767 * 1 is %zu/n", gssim(-32767, 1)); printf("size required for -32768 * 1 is %zu/n", gssim(-32768, 1)); printf("size required for -32769 * 1 is %zu/n", gssim(-32769, 1)); printf("size required for 1000000000 * 2 is %zu/n", gssim(1000000000, 2)); printf("size required for 1250000000 * 2 is %zu/n", gssim(1250000000, 2)); return 0; } size_t gssim(long long a, long long b) { size_t ret_size; if ( same_sign(a, b) ) { if ( (CHAR_MAX / (long double) b) >= a ) { ret_size = 1; } else if ( (SHRT_MAX / (long double) b) >= a ) { ret_size = sizeof(short); } else if ( (INT_MAX / (long double) b) >= a ) { ret_size = sizeof(int); } else if ( (LONG_MAX / (long double) b) >= a ) { ret_size = sizeof(long); } else if ( (LLONG_MAX / (long double) b) >= a ) { ret_size = sizeof(long long); } else { ret_size = 0; } } else { if ( (SCHAR_MIN / (long double) llabs(b)) <= -llabs(a) ) { ret_size = 1; } else if ( (SHRT_MIN / (long double) llabs(b)) <= -llabs(a) ) { ret_size = sizeof(short); } else if ( (INT_MIN / (long double) llabs(b)) <= -llabs(a) ) { ret_size = sizeof(int); } else if ( (LONG_MIN / (long double) llabs(b)) <= -llabs(a) ) { ret_size = sizeof(long); } else if ( (LLONG_MIN / (long double) llabs(b)) <= -llabs(a) ) { ret_size = sizeof(long long); } else { ret_size = 0; } } return ret_size; } int same_sign(long long a, long long b) { if ( (a >= 0 && b >= 0) || (a <= 0 && b <= 0) ) { return 1; } else { return 0; } }

que, en mi sistema, produce:

size required for 127 * 1 is 1 size required for 128 * 1 is 2 size required for 129 * 1 is 2 size required for 127 * -1 is 1 size required for 128 * -1 is 1 size required for 129 * -1 is 2 size required for 32766 * 1 is 2 size required for 32767 * 1 is 2 size required for 32768 * 1 is 4 size required for -32767 * 1 is 2 size required for -32768 * 1 is 2 size required for -32769 * 1 is 4 size required for 1000000000 * 2 is 4 size required for 1250000000 * 2 is 8


Sí, sizeof () no calcula la memoria requerida para el resultado de esa multiplicación.

En el segundo caso, ambos literales: 1250000000 y 2 cada uno requieren 4 bytes de memoria, por lo tanto sizeof () devuelve 4 . Si uno de los valores era superior a 4294967295 (2^32 - 1) , habría obtenido 8 .

Pero no sé cómo sizeof () devolvió 8 por 2500000000 . Devuelve 4 en mi compilador VS2012


[Editar: no me di cuenta, inicialmente, que esto se publicó como C y C ++. Estoy respondiendo solo con respecto a C.]

Respondiendo a su pregunta de seguimiento, "¿Hay alguna forma de determinar la cantidad de memoria asignada a una expresión o variable en tiempo de ejecución?": Bueno, no exactamente. El problema es que esta no es una pregunta muy bien formada.

Las "expresiones", en C-the-language (a diferencia de algunas implementaciones específicas), en realidad no usan ninguna memoria. (Las implementaciones específicas necesitan algún código y / o memoria de datos para guardar cálculos, dependiendo de cuántos resultados caben en los registros de la CPU, etc.) Si un resultado de expresión no está oculto en una variable, simplemente desaparece (y el compilador puede a menudo omite el código de tiempo de ejecución para calcular el resultado nunca guardado). El lenguaje no le ofrece una forma de preguntar sobre algo que no supone que existe, es decir, espacio de almacenamiento para expresiones.

Las variables, por otro lado, ocupan el almacenamiento (memoria). La declaración de una variable le dice al compilador cuánto almacenamiento debe reservar. Sin embargo, a excepción de las matrices de longitud variable C99, el almacenamiento requerido se determina únicamente en tiempo de compilación , no en tiempo de ejecución. Esta es la razón por la cual sizeof x generalmente es una expresión constante: el compilador puede (y de hecho debe) determinar el valor de sizeof x en tiempo de compilación.

Los VLA de C99 son una excepción especial a la regla:

void f(int n) { char buf[n]; ... }

El almacenamiento requerido para buf no es (en general) algo que el compilador pueda encontrar en tiempo de compilación, por lo que sizeof buf no es una constante en tiempo de compilación. En este caso, buf realmente se asigna en tiempo de ejecución y su tamaño solo se determina en ese momento. Entonces sizeof buf es una expresión calculada en tiempo de ejecución.

Para la mayoría de los casos, sin embargo, todo se evalúa desde el principio, en tiempo de compilación, y si una expresión se desborda en el tiempo de ejecución, el comportamiento no está definido, definido por la implementación o bien definido, dependiendo del tipo. El desbordamiento de enteros con signo, como en 2.5 billones multiplicado por 2, cuando INT_MAX es solo un poco más de 2.7 billones, da como resultado un "comportamiento indefinido". Los enteros sin signo hacen una aritmética modular y, por lo tanto, le permiten calcular en GF (2 k ).

Si quiere asegurarse de que algunos cálculos no se desborden, eso es algo que tiene que calcular usted mismo, en tiempo de ejecución. Esta es una gran parte de lo que hace que las bibliotecas de multiprecidad (como gmp) sean difíciles de escribir en C; generalmente es mucho más fácil, así como más rápido, codificar grandes partes en ensamblaje y aprovechar las propiedades conocidas de la CPU (como banderas de desbordamiento, o pares de registros de resultado doblemente anchos).


2500000000 no cabe en un int , por lo que el compilador lo interpreta correctamente como un long (o long long o un tipo donde cabe). 1250000000 hace, y también lo hace 2 . El parámetro a sizeof no se evalúa , por lo que el compilador no puede saber que la multiplicación no cabe en un int , y por lo tanto devuelve el tamaño de un int .

Además, incluso si se evaluó el parámetro, es probable que obtenga un desbordamiento (y un comportamiento indefinido), pero probablemente aún resulte en 4 .

Aquí:

#include <iostream> int main() { long long x = 1250000000 * 2; std::cout << x; }

¿Puedes adivinar la salida? Si crees que es 2500000000 , estarías equivocado. El tipo de la expresión 1250000000 * 2 es int , porque los operandos son int e int y la multiplicación no se promociona automágicamente a un tipo de datos más grande si no encaja.

http://ideone.com/4Adf97

Así que aquí, gcc dice que es -1794967296 , pero es un comportamiento indefinido, por lo que podría ser cualquier número. Este número encaja en un int .

Además, si lanzas uno de los operandos al tipo esperado (al igual que cuando seleccionas enteros al dividir si buscas un resultado no entero), verás que funciona:

#include <iostream> int main() { long long x = (long long)1250000000 * 2; std::cout << x; }

produce el correcto 2500000000 .