¿Qué idioma en el estándar hace que este código funcione, imprimiendo '-1'?
unsigned int u = UINT_MAX; signed int s = u; printf("%d", s);https://en.cppreference.com/w/c/language/conversion
de lo contrario, si el tipo de destino está firmado, el comportamiento está definido por la implementación (lo que puede incluir generar una señal)
https://gcc.gnu.org/onlinedocs/gcc/Integers-implementation.html#Integers-implementation
GCC solo admite tipos enteros en complemento a dos y todos los patrones de bits son valores ordinarios.
El resultado de, o la señal emitida por, convertir un número entero a un tipo de número entero con signo cuando el valor no se puede representar en un objeto de ese tipo (C90 6.2.1.2, C99 y C11 6.3.1.3):
Para la conversión a un tipo de ancho N, el valor se reduce módulo 2^N para estar dentro del rango del tipo; no se levanta ninguna señal.
Para mí, parece que convertir UINT_MAX en un int significaría dividir UINT_MAX por 2^(CHAR_BIT * sizeof(int)) . En aras del argumento, con entradas de 32 bits, 0xFFFFFFFF / 2^32 = 0xFFFFFFFF . Entonces, esto realmente no explica cómo el valor '-1' termina en el int .
¿Hay algún otro lenguaje en algún otro lugar que diga que después de la división del módulo simplemente reinterpretamos los bits? ¿O alguna otra parte del estándar que tiene prioridad sobre las partes a las que me he referido?
Ninguna parte del estándar C garantiza que su código imprima -1 en general. Como dice, el resultado de la conversión está definido por la implementación. Sin embargo, la documentación de GCC promete que si compila con su implementación, su código imprimirá -1. No tiene nada que ver con patrones de bits, solo matemáticas.
La lectura claramente intencionada de "módulo reducido 2 ^ N" en el manual de GCC es que el resultado debe ser el número único en el rango de signed int con signo que es congruente mod 2 ^ N con la entrada. Esta es una forma matemática precisa de definir el comportamiento de "envoltura" que espera, que coincide con lo que obtendría al reinterpretar los bits.
Suponiendo 32 bits, UINT_MAX tiene el valor 4294967295. Esta es una modificación congruente de 4294967296 a -1. Es decir, la diferencia entre 4294967295 y -1 es un múltiplo de 4294967296, es decir, 4294967296 mismo. Además, este es necesariamente el número único en [-2147483648, 2147483647]. (Cualquier otro número congruente con -1 sería al menos -1 + 4294967296 = 4294967295 , o como máximo -1 - 4294967296 = -4294967297 ). Entonces -1 es el resultado de la conversión.
En otras palabras, sume o reste 4294967296 repetidamente hasta que obtenga un número que esté en el rango de signed int con signo. Se garantiza que hay exactamente uno de esos números, y en este caso es -1.