Dado por um colega como um quebra-cabeça, não consigo descobrir como esse programa C realmente compila e executa. O que é esse >>>=
operador e o 1P1
literal estranho ? Eu testei em Clang e GCC. Não há avisos e a saída é "???"
#include <stdio.h>
int main()
{
int a[2]={ 10, 1 };
while( a[ 0xFULL?'\0':-1:>>>=a<:!!0X.1P1 ] )
printf("?");
return 0;
}
0x.1P1
é um literal hexadecimal com um expoente. A0x.1
é a parte do número, ou 1/16 aqui. O número após o 'P' é a potência de dois, multiplicado pelo número. Então0x.1p1
é realmente 1/16 * 2 ou 1/8. E se você estava pensando sobre0xFULL
isso é apenas0xF
, eULL
é o sufixo para umunsigned long long
Respostas:
A linha:
contém os digrafos
:>
e<:
, que se traduzem para]
e[
respectivamente, portanto, é equivalente a:O literal
0xFULL
é o mesmo que0xF
(que é hexadecimal para15
); oULL
just especifica que é umunsigned long long
literal . De qualquer forma, como booleano é verdade, é0xFULL ? '\0' : -1
avaliado como'\0'
, que é um literal de caractere cujo valor numérico é simplesmente0
.Enquanto isso,
0X.1P1
é um literal de ponto flutuante hexadecimal igual a 2/16 = 0,125. De qualquer forma, sendo diferente de zero, também é verdadeiro como um booleano, portanto, negá-lo duas vezes com!!
novamente produz1
. Assim, tudo simplifica:O operador
>>=
é uma atribuição composta que desloca o operando esquerdo para a direita pelo número de bits fornecido pelo operando direito e retorna o resultado. Nesse caso, o operando certoa[1]
sempre tem o valor1
, portanto é equivalente a:ou equivalente:
O valor inicial de
a[0]
é 10. Depois de mudar para a direita uma vez, torna-se 5, depois (arredondando para baixo) 2, depois 1 e finalmente 0, altura em que o loop termina. Assim, o corpo do loop é executado três vezes.fonte
P
no0X.1P1
.e
em10e5
, exceto que você tem que usarp
para literais hexadecimais, porquee
é um dígito hexadecimal.p
separa a mantissa e o expoente, exatamente comoe
na notação científica normal; uma diferença é que, com flutuadores hexadecimais, a base da parte exponencial é 2 em vez de 10, então0x0.1p1
é igual a 0x0,1 = 1/16 vezes 2¹ = 2. (De qualquer forma, nada disso importa aqui; qualquer valor diferente de zero valor funcionaria igualmente bem lá).char
literal" e adicionei um link da Wikipedia. Obrigado!É um código bastante obscuro que envolve dígrafos , a saber,
<:
e:>
que são tokens alternativos para[
e]
respectivamente. Também há algum uso do operador condicional . Há também um operador de troca de marchas, a atribuição de troca certa>>=
.Esta é uma versão mais legível:
e uma versão ainda mais legível, substituindo as expressões no
[]
pelos valores que eles resolvem:A substituição
a[0]
ea[1]
por seus valores deve facilitar a compreensão do que o loop está fazendo, ou seja, o equivalente a:que está simplesmente executando a divisão (inteira) por 2 em cada iteração, produzindo a sequência
5, 2, 1
.fonte
????
, e não???
como o OP conseguiu? (Hum.) Codepad.org/nDkxGUNi faz produto???
.Vamos passar pela expressão da esquerda para a direita:
A primeira coisa que noto é que estamos usando o operador ternário do uso de
?
. Então a subexpressão:está dizendo "se
0xFULL
for diferente de zero, retorne'\0'
, caso contrário-1
.0xFULL
é um literal hexadecimal com o sufixo longo não assinado - o que significa que é um literal hexadecimal do tipounsigned long long
. Isso realmente não importa, porque0xF
pode caber dentro de um número inteiro regular.Além disso, o operador ternário converte os tipos do segundo e do terceiro termos no tipo comum.
'\0'
é então convertido paraint
, o que é justo0
.O valor de
0xF
é muito maior que zero, então passa. A expressão agora se torna:Em seguida,
:>
é um dígrafo . É uma construção que se expande para]
:>>=
é o operador de turno certo assinado, podemos separá-loa
para torná-lo mais claro.Além disso,
<:
é um dígrafo que se expande para[
:0X.1P1
é um literal hexadecimal com um expoente. Mas não importa o valor, o valor!!
de qualquer coisa que não seja zero é verdadeiro.0X.1P1
é0.125
que é diferente de zero, então ele se torna:O
>>=
é o operador de turno certo assinado. Ele altera o valor do seu operando esquerdo, deslocando seus bits para a frente pelo valor no lado direito do operador.10
em binário é1010
. Então, aqui estão as etapas:>>=
retorna o resultado de sua operação, desde que o deslocamentoa[0]
permaneça diferente de zero para cada vez que seus bits forem deslocados para a direita em um, o loop continuará. A quarta tentativa é ondea[0]
fica0
, então o loop nunca é inserido.Como resultado,
?
é impresso três vezes.fonte
:>
é um dígrafo , não um trigrafo. Não é manipulado pelo pré-processador, é simplesmente reconhecido como um token equivalente a]
.?:
) tem um tipo que é o tipo comum do segundo e terceiro termos. O primeiro termo é sempre uma condição e tem um tipobool
. Como o segundo e o terceiro termos têm o tipo,int
o resultado da operação ternária seráint
, nãounsigned long long
.#
e##
tem dígrafo formas; não há nada que uma implementação de traduzir dígrafos a não dígrafos durante as fases de tradução iniciais