tipos long float datos data c types

c - float - unsigned long



¿Por qué el int más pequeño, −2147483648, tiene el tipo ''long''? (2)

Esta pregunta ya tiene una respuesta aquí:

Para un proyecto escolar, tengo que codificar la función C printf. Las cosas van bastante bien, pero hay una pregunta para la que no puedo encontrar una buena respuesta, así que aquí estoy.

printf("PRINTF(d) /t: %d/n", -2147483648);

me dice ( gcc -Werror -Wextra -Wall ):

error: format specifies type ''int'' but the argument has type ''long'' [-Werror,-Wformat] printf("PRINTF(d) /t: %d/n", -2147483648); ~~ ^~~~~~~~~~~ %ld

Pero si uso una variable int, todo va bien:

int i; i = -2147483648; printf("%d", i);

¿Por qué?

EDITAR:

Entendí muchos puntos, y fueron muy interesantes. De todos modos, supongo que printf está usando <stdarg.h> librairy y, por lo tanto, va_arg(va_list ap, type) también debería devolver el tipo correcto. Para %d y %i , obviamente el tipo devuelto es un int . ¿Cambia algo?


El problema es que -2147483648 no es un entero literal. Es una expresión que consiste en el operador de negación unario - y el número entero 2147483648 , que es demasiado grande para ser un int si int s son 32 bits. Como el compilador elegirá un número entero con el tamaño adecuado para representar 2147483648 antes de aplicar el operador de negación, el tipo de resultado será mayor que un int .

Si sabe que sus int s son de 32 bits y desea evitar la advertencia sin mutilar la legibilidad, use un reparto explícito:

printf("PRINTF(d) /t: %d/n", (int)(-2147483648));

Ese es el comportamiento definido en una máquina de complemento de 2 con int s de 32 bits.

Para una mayor portabilidad teórica, use INT_MIN lugar del número y díganos dónde encontró una máquina que no sea un complemento de 2 para probarla.

Para ser claros, ese último párrafo fue en parte una broma. INT_MIN es definitivamente el camino a seguir si te refieres a "el int más pequeño", porque int varía en tamaño. Todavía hay muchas implementaciones de 16 bits, por ejemplo. Escribir -2 31 solo es útil si definitivamente siempre quiere decir con precisión ese valor, en cuyo caso probablemente usaría un tipo de tamaño fijo como int32_t lugar de int .

Es posible que desee alguna alternativa a escribir el número en decimal para que sea más claro para aquellos que no noten la diferencia entre 2147483648 y 2174483648 , pero deben tener cuidado.

Como se mencionó anteriormente, en una máquina de 32 bits con 2 complementos, (int)(-2147483648) no se desbordará y, por lo tanto, está bien definido, porque -2147483648 tratará como un tipo con signo más amplio. Sin embargo, lo mismo no es cierto para (int)(-0x80000000) . 0x80000000 se tratará como un unsigned int (ya que se ajusta a la representación sin signo); -0x80000000 está bien definido (pero el - no tiene efecto si int es de 32 bits), y la conversión del unsigned int 0x80000000 unsigned int resultante a int implica un desbordamiento. Para evitar el desbordamiento, necesitaría convertir la constante hexadecimal a un tipo con signo: (int)(-(long long)(0x80000000)) .

Del mismo modo, debe tener cuidado si desea utilizar el operador de desplazamiento a la izquierda. 1<<31 es un comportamiento indefinido en máquinas de 32 bits con int s de 32 bits (o más pequeños); solo se evaluará a 2 31 si int tiene al menos 33 bits, porque el desplazamiento a la izquierda por k bits solo está bien definido si k es estrictamente menor que el número de bits sin signo del tipo entero del argumento de la izquierda.

1LL<<31 es seguro, ya que se requiere long long int para poder representar 2 63 -1, por lo que su tamaño de bits debe ser mayor que 32. Entonces, la forma

(int)(-(1LL<<31))

Es posiblemente el más legible. YMMV.

Para cualquier pedante que pase, esta pregunta está etiquetada con C, y el último borrador de C (n1570.pdf) dice, con respecto a E1 << E2 , donde E1 tiene un tipo con signo, que el valor se define solo si E1 no es negativo y E1 × 2 E2 "es representable en el tipo de resultado". (§6.5.7 para 4).

Eso es diferente de C ++, en el que la aplicación del operador de desplazamiento a la izquierda se define si E1 no es negativo y E1 × 2 E2 "es representable en el tipo correspondiente sin signo del tipo de resultado" (§5.8 párr. 2, énfasis agregado).

En C ++, de acuerdo con el borrador del estándar más reciente, la conversión de un valor entero a un tipo entero con signo se define en la implementación si el valor no se puede representar en el tipo de destino (§4.7 párr. 3). El párrafo correspondiente de la norma C - §6.3.1.3 párr. 3 - dice que "o bien el resultado está definido por la implementación o se genera una señal definida por la implementación".)


En C, -2147483648 no es una constante entera. 2147483648 es una constante entera, y - es solo un operador unario aplicado a ella, produciendo una expresión constante. El valor de 2147483648 no cabe en un int (es demasiado grande, 2147483647 suele ser el número entero más grande) y, por lo tanto, la constante entera tiene un tipo long , lo que causa el problema que observa. Si desea mencionar el límite inferior para un int , use la macro INT_MIN de <limits.h> (el enfoque portátil) o evite mencionar 2147483648 cuidado:

printf("PRINTF(d) /t: %d/n", -1 - 2147483647);