De-offuscarlo.
Rientro:
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
Presentazione delle variabili per districare questo casino:
main(int i) {
if(i^448)
main(-~i);
if(--i % 64) {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
} else {
putchar(10); // newline
}
}
Si noti che a -~i == i+1
causa del complemento a due. Pertanto, abbiamo
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = -~7[__TIME__-i/8%8][">'txiZ^(~z?"-48];
char b = a >> ";;;====~$::199"[i*2&8|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
Ora, nota che a[b]
è lo stesso dib[a]
e applica -~ == 1+
nuovamente la modifica:
main(int i) {
if(i != 448)
main(i+1);
i--;
if(i % 64 == 0) {
putchar('\n');
} else {
char a = (">'txiZ^(~z?"-48)[(__TIME__-i/8%8)[7]] + 1;
char b = a >> ";;;====~$::199"[(i*2&8)|i/64]/(i&2?1:8)%8;
putchar(32 | (b & 1));
}
}
Convertire la ricorsione in un ciclo e semplificare un po 'di più:
// please don't pass any command-line arguments
main() {
int i;
for(i=447; i>=0; i--) {
if(i % 64 == 0) {
putchar('\n');
} else {
char t = __TIME__[7 - i/8%8];
char a = ">'txiZ^(~z?"[t - 48] + 1;
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
if((i & 2) == 0)
shift /= 8;
shift = shift % 8;
char b = a >> shift;
putchar(32 | (b & 1));
}
}
}
Questo genera un carattere per iterazione. Ogni 64 ° carattere, genera una nuova riga. In caso contrario, utilizza una coppia di tabelle di dati per capire cosa produrre e inserisce il carattere 32 (uno spazio) o il carattere 33 (a !
). La prima tabella ( ">'txiZ^(~z?"
) è un insieme di 10 bitmap che descrivono l'aspetto di ciascun carattere e la seconda tabella ( ";;;====~$::199"
) seleziona il bit appropriato da visualizzare dalla bitmap.
Il secondo tavolo
Iniziamo esaminando la seconda tabella, int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
è il numero di riga (da 6 a 0) ed i*2&8
è 8 sef i
è 4, 5, 6 o 7 mod 8.
if((i & 2) == 0) shift /= 8; shift = shift % 8
seleziona la cifra ottale alta (per i%8
= 0,1,4,5) o la cifra ottale bassa (per i%8
= 2,3,6,7) del valore della tabella. La tabella dei turni si presenta così:
row col val
6 6-7 0
6 4-5 0
6 2-3 5
6 0-1 7
5 6-7 1
5 4-5 7
5 2-3 5
5 0-1 7
4 6-7 1
4 4-5 7
4 2-3 5
4 0-1 7
3 6-7 1
3 4-5 6
3 2-3 5
3 0-1 7
2 6-7 2
2 4-5 7
2 2-3 3
2 0-1 7
1 6-7 2
1 4-5 7
1 2-3 3
1 0-1 7
0 6-7 4
0 4-5 4
0 2-3 3
0 0-1 7
o in forma tabulare
00005577
11775577
11775577
11665577
22773377
22773377
44443377
Si noti che l'autore ha utilizzato il terminatore null per le prime due voci della tabella (subdolo!).
Questo è progettato dopo un display a sette segmenti, con 7
s come spazi vuoti. Pertanto, le voci nella prima tabella devono definire i segmenti che si illuminano.
Il primo tavolo
__TIME__
è una macro speciale definita dal preprocessore. Si espande in una costante di stringa contenente l'ora in cui è stato eseguito il preprocessore, nel modulo "HH:MM:SS"
. Osserva che contiene esattamente 8 caratteri. Si noti che 0-9 ha valori ASCII da 48 a 57 e :
ha valore ASCII 58. L'output è di 64 caratteri per riga, quindi lascia 8 caratteri per carattere di __TIME__
.
7 - i/8%8
è quindi l'indice di __TIME__
quello che viene attualmente prodotto ( 7-
è necessario perché stiamo iterando i
verso il basso). Quindi, t
è il carattere di __TIME__
essere prodotto.
a
finisce per eguagliare quanto segue in binario, a seconda dell'input t
:
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
Ogni numero è una bitmap che descrive i segmenti illuminati nel nostro display a sette segmenti. Poiché i caratteri sono tutti ASCII a 7 bit, il bit alto viene sempre azzerato. Pertanto, 7
nella tabella dei segmenti viene sempre stampato come vuoto. La seconda tabella si presenta così con la 7
s come spazi vuoti:
000055
11 55
11 55
116655
22 33
22 33
444433
Quindi, per esempio, 4
è 01101010
(set di bit 1, 3, 5 e 6), che stampa come
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
Per mostrare che capiamo davvero il codice, regoliamo un po 'l'output con questa tabella:
00
11 55
11 55
66
22 33
22 33
44
Questo è codificato come "?;;?==? '::799\x07"
. Per scopi artistici, aggiungeremo 64 ad alcuni dei caratteri (poiché vengono utilizzati solo i 6 bit bassi, ciò non influirà sull'output); questo dà "?{{?}}?gg::799G"
(nota che l'ottavo personaggio è inutilizzato, quindi possiamo effettivamente farlo come vogliamo). Mettendo la nostra nuova tabella nel codice originale:
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
noi abbiamo
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
proprio come ci aspettavamo. Non è così solido come l'originale, il che spiega perché l'autore abbia scelto di usare il tavolo che ha fatto.
printf("%d", _);
all'inizio dellemain
stampe: pastebin.com/HHhXAYdJ