Lassen Sie es uns verschleiern.
Einrücken:
main(_) {
_^448 && main(-~_);
putchar(--_%64
? 32 | -~7[__TIME__-_/8%8][">'txiZ^(~z?"-48] >> ";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1
: 10);
}
Einführung von Variablen, um dieses Durcheinander zu entwirren:
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
}
}
Beachten Sie, dass -~i == i+1
wegen Zweierkomplement. Deshalb haben wir
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));
}
}
Beachten Sie nun, dass dies a[b]
dasselbe ist wieb[a]
, und wenden Sie die -~ == 1+
Änderung erneut an:
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));
}
}
Konvertieren Sie die Rekursion in eine Schleife und schleichen Sie sich etwas vereinfachter:
// 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));
}
}
}
Dies gibt ein Zeichen pro Iteration aus. Jedes 64. Zeichen gibt eine neue Zeile aus. Andernfalls werden zwei Datentabellen verwendet, um herauszufinden, was ausgegeben werden soll, und entweder das Zeichen 32 (ein Leerzeichen) oder das Zeichen 33 (a !
) eingefügt. Die erste Tabelle ( ">'txiZ^(~z?"
) besteht aus 10 Bitmaps, die das Erscheinungsbild jedes Zeichens beschreiben, und die zweite Tabelle ( ";;;====~$::199"
) wählt das entsprechende Bit aus der Bitmap aus.
Der zweite Tisch
Beginnen wir mit der Untersuchung der zweiten Tabelle int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
. i/64
ist die Zeilennummer (6 bis 0) und i*2&8
ist 8, wenn i
4, 5, 6 oder 7 mod 8 ist.
if((i & 2) == 0) shift /= 8; shift = shift % 8
wählt entweder die hohe Oktalstelle (für i%8
= 0,1,4,5) oder die niedrige Oktalstelle (für i%8
= 2,3,6,7) des Tabellenwerts aus. Der Schichttisch sieht am Ende so aus:
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
oder in tabellarischer Form
00005577
11775577
11775577
11665577
22773377
22773377
44443377
Beachten Sie, dass der Autor den Null-Terminator für die ersten beiden Tabelleneinträge verwendet hat (hinterhältig!).
Dies ist nach einer Sieben-Segment-Anzeige mit 7
s als Leerzeichen ausgelegt. Die Einträge in der ersten Tabelle müssen also die Segmente definieren, die beleuchtet werden.
Der erste Tisch
__TIME__
ist ein spezielles Makro, das vom Präprozessor definiert wird. Es wird in der Form zu einer Zeichenfolgenkonstante erweitert, die den Zeitpunkt enthält, zu dem der Präprozessor ausgeführt wurde "HH:MM:SS"
. Beachten Sie, dass es genau 8 Zeichen enthält. Beachten Sie, dass 0-9 die ASCII-Werte 48 bis 57 und :
den ASCII-Wert 58 haben. Die Ausgabe beträgt 64 Zeichen pro Zeile, sodass 8 Zeichen pro Zeichen von übrig bleiben __TIME__
.
7 - i/8%8
ist also der Index, der __TIME__
gerade ausgegeben wird (der 7-
wird benötigt, weil wir nach i
unten iterieren ). So t
ist der Charakter der __TIME__
Ausgabe.
a
Abhängig von der Eingabe entspricht dies in Binärform dem Folgenden t
:
0 00111111
1 00101000
2 01110101
3 01111001
4 01101010
5 01011011
6 01011111
7 00101001
8 01111111
9 01111011
: 01000000
Jede Zahl ist eine Bitmap , die die Segmente beschreibt, die in unserer Sieben-Segment-Anzeige leuchten. Da die Zeichen alle 7-Bit-ASCII sind, wird das High-Bit immer gelöscht. Daher wird 7
in der Segmenttabelle immer als Leerzeichen gedruckt. Die zweite Tabelle sieht so aus, mit dem 7
s als Leerzeichen:
000055
11 55
11 55
116655
22 33
22 33
444433
So zum Beispiel 4
ist 01101010
(Bits 1, 3, 5 und 6 gesetzt), die als Druck
----!!--
!!--!!--
!!--!!--
!!!!!!--
----!!--
----!!--
----!!--
Um zu zeigen, dass wir den Code wirklich verstehen, passen wir die Ausgabe mit dieser Tabelle ein wenig an:
00
11 55
11 55
66
22 33
22 33
44
Dies ist codiert als "?;;?==? '::799\x07"
. Für künstlerische Zwecke fügen wir einigen Zeichen 64 hinzu (da nur die niedrigen 6 Bits verwendet werden, wirkt sich dies nicht auf die Ausgabe aus). Dies gibt "?{{?}}?gg::799G"
(beachten Sie, dass das 8. Zeichen nicht verwendet wird, so dass wir es tatsächlich machen können, was wir wollen). Fügen Sie unsere neue Tabelle in den Originalcode ein:
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>"?{{?}}?gg::799G"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
wir bekommen
!! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !! !!
!! !! !!
genau wie wir erwartet hatten. Es sieht nicht so solide aus wie das Original, was erklärt, warum der Autor die Tabelle verwendet hat, die er gemacht hat.
printf("%d", _);
zum Anfang dermain
Drucke: pastebin.com/HHhXAYdJ