Solución:
C ª, -2147483648
no es una constante entera. 2147483648
es una constante entera, y -
es solo un operador unario que se le aplica, lo que produce una expresión constante. El valor de 2147483648
no encaja en un int
(es demasiado grande, 2147483647
es típicamente el número entero más grande) y, por lo tanto, la constante entera tiene el tipo long
, que causa el problema que observa. Si desea mencionar el límite inferior de un int
, usa la macro INT_MIN
de <limits.h>
(el enfoque portátil) o evite cuidadosamente mencionar 2147483648
:
printf("PRINTF(d) t: %dn", -1 - 2147483647);
El problema es ese -2147483648
no es un literal entero. Es una expresión que consta del operador de negación unario. -
y el entero 2147483648
, que es demasiado grande para ser un int
si int
s son 32 bits. Dado que el compilador elegirá un entero con signo de tamaño apropiado para representar 2147483648
antes de aplicar el operador de negación, el tipo de resultado será mayor que un int
.
Si sabes que tu int
s son de 32 bits y desea evitar la advertencia sin mutilar la legibilidad, use una conversión explícita:
printf("PRINTF(d) t: %dn", (int)(-2147483648));
Ese es el comportamiento definido en una máquina en complemento a 2 con 32 bits int
s.
Para una mayor portabilidad teórica, utilice INT_MIN
en lugar del número, y háganos saber dónde encontró una máquina que no sea complemento a 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 más pequeño int
“, porque int
varía en tamaño. Todavía hay muchas implementaciones de 16 bits, por ejemplo. Escribiendo -231 solo es útil si definitivamente siempre te refieres exactamente a ese valor, en cuyo caso probablemente usarías un tipo de tamaño fijo como int32_t
en 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 tienes que tener cuidado.
Como se mencionó anteriormente, en una máquina de complemento a 2 de 32 bits, (int)(-2147483648)
no se desbordará y, por lo tanto, está bien definido, porque -2147483648
se tratará como un tipo firmado más amplio. Sin embargo, no ocurre lo mismo con (int)(-0x80000000)
. 0x80000000
será tratado como un unsigned int
(ya que encaja en la representación sin firmar); -0x80000000
está bien definido (pero el -
no tiene efecto si int
es de 32 bits), y la conversión de la resultante unsigned int
0x80000000
para int
implica un desbordamiento. Para evitar el desbordamiento, necesitaría convertir la constante hexadecimal a un tipo firmado: (int)(-(long long)(0x80000000))
.
Del mismo modo, debe tener cuidado si desea utilizar el operador de cambio a la izquierda. 1<<31
es un comportamiento indefinido en máquinas de 32 bits con 32 bits (o menos) int
s; solo evaluará a 231 si int
es de 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 long long int
se requiere poder representar 263-1, por lo que su tamaño de bits debe ser mayor que 32. Por lo tanto, el formulario
(int)(-(1LL<<31))
es posiblemente el más legible. YMMV.
Para cualquier pedante que apruebe, esta pregunta está etiquetada como C, y el último borrador de C (n1570.pdf) dice, con respecto a E1 << E2
, dónde E1
tiene un tipo firmado, que el valor se define solo si E1
es no negativo y E1 × 2E2
“se puede representar en el tipo de resultado”. (§6.5.7 párrafo 4).
Eso es diferente de C ++, en el que la aplicación del operador de desplazamiento a la izquierda se define si E1
es no negativo y E1 × 2E2
“es representable
en el tipo sin firmar correspondiente del tipo de resultado “(§5.8 párr. 2, énfasis añadido).
En C ++, de acuerdo con el borrador de estándar más reciente, la conversión de un valor entero a un tipo entero con signo es definido por 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 el resultado está definido por la implementación o se genera una señal definida por la implementación”.)