How does this C program work?
main(_){_^448&&main(-~_);putchar(--_%64?32|-~7[__TIME__-_/8%8][">'txiZ^(~z?"-48]>>";;;====~$::199"[_*2&8|_/64]/(_&2?1:8)%8&1:10);}
It compiles as it is (tested on gcc 4.6.3
). It prints the time when compiled. On my system:
!! !!!!!! !! !!!!!! !! !!!!!!
!! !! !! !! !! !! !! !!
!! !! !! !! !! !! !! !!
!! !!!!!! !! !! !! !! !! !!!!!!
!! !! !! !! !! !! !!
!! !! !! !! !! !! !!
!! !!!!!! !! !! !! !!!!!!
Source: sykes2 – A clock in one line, sykes2 author hints
Some hints: No compile warnings per default. Compiled with -Wall
, the following warnings are emitted:
sykes2.c:1:1: warning: return type defaults to ‘int’ [-Wreturn-type]
sykes2.c: In function ‘main’:
sykes2.c:1:14: warning: value computed is not used [-Wunused-value]
sykes2.c:1:1: warning: implicit declaration of function ‘putchar’ [-Wimplicit-function-declaration]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: suggest parentheses around arithmetic in operand of ‘|’ [-Wparentheses]
sykes2.c:1:1: warning: control reaches end of non-void function [-Wreturn-type]
Best Answer
Let's de-obfuscate it.
Indenting:
Introducing variables to untangle this mess:
Note that
-~i == i+1
because of twos-complement. Therefore, we haveNow, note that
a[b]
is the same asb[a]
, and apply the-~ == 1+
change again:Converting the recursion to a loop and sneaking in a bit more simplification:
This outputs one character per iteration. Every 64th character, it outputs a newline. Otherwise, it uses a pair of data tables to figure out what to output, and puts either character 32 (a space) or character 33 (a
!
). The first table (">'txiZ^(~z?"
) is a set of 10 bitmaps describing the appearance of each character, and the second table (";;;====~$::199"
) selects the appropriate bit to display from the bitmap.The second table
Let's start by examining the second table,
int shift = ";;;====~$::199"[(i*2&8) | (i/64)];
.i/64
is the line number (6 to 0) andi*2&8
is 8 iffi
is 4, 5, 6 or 7 mod 8.if((i & 2) == 0) shift /= 8; shift = shift % 8
selects either the high octal digit (fori%8
= 0,1,4,5) or the low octal digit (fori%8
= 2,3,6,7) of the table value. The shift table ends up looking like this:or in tabular form
Note that the author used the null terminator for the first two table entries (sneaky!).
This is designed after a seven-segment display, with
7
s as blanks. So, the entries in the first table must define the segments that get lit up.The first table
__TIME__
is a special macro defined by the preprocessor. It expands to a string constant containing the time at which the preprocessor was run, in the form"HH:MM:SS"
. Observe that it contains exactly 8 characters. Note that 0-9 have ASCII values 48 through 57 and:
has ASCII value 58. The output is 64 characters per line, so that leaves 8 characters per character of__TIME__
.7 - i/8%8
is thus the index of__TIME__
that is presently being output (the7-
is needed because we are iteratingi
downwards). So,t
is the character of__TIME__
being output.a
ends up equalling the following in binary, depending on the inputt
:Each number is a bitmap describing the segments that are lit up in our seven-segment display. Since the characters are all 7-bit ASCII, the high bit is always cleared. Thus,
7
in the segment table always prints as a blank. The second table looks like this with the7
s as blanks:So, for example,
4
is01101010
(bits 1, 3, 5, and 6 set), which prints asTo show we really understand the code, let's adjust the output a bit with this table:
This is encoded as
"?;;?==? '::799\x07"
. For artistic purposes, we'll add 64 to a few of the characters (since only the low 6 bits are used, this won't affect the output); this gives"?{{?}}?gg::799G"
(note that the 8th character is unused, so we can actually make it whatever we want). Putting our new table in the original code:we get
just as we expected. It's not as solid-looking as the original, which explains why the author chose to use the table he did.