Dado por un colega como un rompecabezas, no puedo entender cómo este programa C realmente compila y se ejecuta. ¿Qué es este >>>=operador y el extraño 1P1literal? He probado en Clang y GCC. No hay advertencias y la salida es "???"
#include <stdio.h>
int main()
{
int a[2]={ 10, 1 };
while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
printf("?");
return 0;
}

0x.1P1es un literal hexadecimal con un exponente. El0x.1es la parte del número, o 1/16 aquí. El número después de la 'P' es la potencia de dos, el número se multiplica por. Entonces0x.1p1es realmente 1/16 * 2, o 1/8. Y si te estabas preguntando acerca de0xFULLeso es justo0xF, yULLes el sufijo para ununsigned long longRespuestas:
La línea:
contiene los dígrafos
:>y<:, que se traducen a]y[respectivamente, por lo que es equivalente a:El literal
0xFULLes el mismo que0xF(que es hexadecimal15); elULLsolo especifica que es ununsigned long longliteral . En cualquier caso, como booleano es cierto, así se0xFULL ? '\0' : -1evalúa como'\0', que es un carácter literal cuyo valor numérico es simplemente0.Mientras tanto,
0X.1P1es un literal de coma flotante hexadecimal igual a 2/16 = 0.125. En cualquier caso, al ser distinto de cero, también es cierto como un booleano, por lo que negarlo dos veces con!!nuevamente produce1. Por lo tanto, todo se simplifica a:El operador
>>=es una asignación compuesta que desplaza su operando izquierdo hacia la derecha por el número de bits dados por el operando derecho y devuelve el resultado. En este caso, el operando correctoa[1]siempre tiene el valor1, por lo que es equivalente a:o equivalente:
El valor inicial de
a[0]es 10. Después de desplazarse a la derecha una vez, se convierte en 5, luego (redondeando hacia abajo) 2, luego 1 y finalmente 0, en cuyo punto finaliza el ciclo. Por lo tanto, el cuerpo del bucle se ejecuta tres veces.fuente
Pen0X.1P1.een10e5, excepto que tiene que usarppara literales hexadecimales porqueees un dígito hexadecimal.psepara la mantisa y el exponente, al igual queeen la notación científica flotante normal; Una diferencia es que, con flotadores hexagonales, la base de la parte exponencial es 2 en lugar de 10, por lo que0x0.1p1es igual a 0x0.1 = 1/16 veces 2¹ = 2. (En cualquier caso, nada de eso importa aquí; el valor funcionaría igual de bien allí.)charliteral", y agregué un enlace de Wikipedia. ¡Gracias!Es un código bastante oscuro que involucra dígrafos , a saber,
<:y:>que son tokens alternativos para[y]respectivamente. También hay algún uso del operador condicional . También hay un operador de desplazamiento leve , la asignación de desplazamiento correcta>>=.Esta es una versión más legible:
y una versión aún más legible, reemplazando las expresiones en
[]los valores por los que resuelven:Reemplazar
a[0]ya[1]por sus valores debería facilitar la comprensión de lo que está haciendo el ciclo, es decir, el equivalente de:que simplemente realiza la división (entera) por 2 en cada iteración, produciendo la secuencia
5, 2, 1.fuente
????, sin embargo, en lugar de lo que???obtuvo el OP? (Huh.) Codepad.org/nDkxGUNi hace productos???.Veamos la expresión de izquierda a derecha:
Lo primero que noto es que estamos usando el operador ternario del uso de
?. Entonces la subexpresión:dice "si
0xFULLno es cero, return'\0', de lo contrario-1.0xFULLes un literal hexadecimal con el sufijo largo largo sin signo , lo que significa que es un literal hexadecimal de tipounsigned long long. Sin embargo, eso realmente no importa, porque0xFpuede caber dentro de un entero regular.Además, el operador ternario convierte los tipos del segundo y tercer término a su tipo común.
'\0'luego se convierte aint, que es justo0.El valor de
0xFes mucho mayor que cero, por lo que pasa. La expresión ahora se convierte en:A continuación,
:>hay un dígrafo . Es una construcción que se expande a]:>>=es el operador de desplazamiento a la derecha firmado, podemos espaciarloapara aclararlo.Además,
<:es un dígrafo que se expande a[:0X.1P1es un literal hexadecimal con un exponente. Pero no importa el valor,!!todo lo que no sea cero es cierto.0X.1P1es0.125que no es cero, por lo que se convierte en:El
>>=es el operador de desplazamiento a la derecha firmado. Cambia el valor de su operando izquierdo desplazando sus bits hacia adelante por el valor en el lado derecho del operador.10en binario es1010. Así que aquí están los pasos:>>=devuelve el resultado de su operación, de modo que mientras el desplazamientoa[0]permanezca distinto de cero por cada vez que sus bits se desplacen uno a la derecha, el bucle continuará. El cuarto intento es donde sea[0]hace0, por lo que el ciclo nunca se ingresa.Como resultado,
?se imprime tres veces.fuente
:>es un dígrafo , no un trigrafo. No es manejado por el preprocesador, simplemente se reconoce como un token equivalente a].?:) tiene un tipo que es el tipo común de los términos segundo y tercero. El primer término es siempre condicional y tiene un tipobool. Dado que tanto el segundo como el tercer término tienen tipo,intel resultado de la operación ternaria seráint, nounsigned long long.#y##tiene formas de dígrafo; no hay nada que impida que una implementación traduzca dígrafos a no dígrafos durante las primeras fases de traducción