This classic ioccc entry is a Hello World program written in C. Can anyone please provide an explanation of how it works?
Original code (syntax highlighting intentionally missing):
int i;main(){for(;i["]<i;++i){--i;}"];read('-'-'-',i+++"hell\ o, world!\n",'/'/'/'));}read(j,i,p){write(j/p+p,i---j,i/i);}
Slightly cleaner:
int i; main() { for ( ; i["]<i;++i){--i;}"]; read('-' - '-', i++ + "hello, world!\n", '/' / '/')); } read(j, i, p) { write(j / p + p, i-- - j, i / i); }
Traditionally, Hello World programs are used to illustrate how the process of coding works, as well as to ensure that a language or system is operating correctly. They are usually the first programs that new coders learn, because even those with little or no experience can execute Hello World both easily and correctly.
Where exactly did Hello World originate? It's creator, Brian Kernighan, authored one of the most widely read programming books, C Programming Language. He first referenced Hello World in his book titled A Tutorial Introduction to the Programming Language B.
printf("Hello World"); This line tells the compiler to display the message "Hello World" on the screen. This line is called a statement in C. Every statement is meant to perform some task.
i["]<i;++i){--i;}"]
This expression takes advantage of the fact that array indexing is commutative in C. It is equivalent to.
"]<i;++i){--i;}"[i]
So the loop will terminate when the character at position i
is \0
, i.e., at the end of the string, which is 14 characters long (which happens to be the same length as "hello, world!\n"). So the for
loop condition can be rewritten as:
i != 14
read('-' - '-', i++ + "hello, world!\n", '/' / '/')
char
is an integer type, and thus:
'-' - '-'
is 0'/' / '/'
is 1
read(0, i++ + "hello, world!\n", 1)
After fixing all the compiler warnings (like implicit int to pointer conversion), and simplifying the things mentioned above, the code becomes:
#include <unistd.h> int i = 0; void read2(int, char*, int); int main() { while (i != 14) { read2(0, i++ + "hello, world!\n", 1); } return 0; } void read2(int j, char* i, int p) { write(j / p + p, i-- - j, 1); }
(I renamed read
to read2
to avoid conflicting with the Unix read
function.)
Note that the j
and p
arguments to read2
are unneeded, as the function is always called with j=0 and p=1.
#include <unistd.h> int i = 0; void read2(char*); int main() { while (i != 14) { read2(i++ + "hello, world!\n"); } return 0; } void read2(char* i) { write(1, i--, 1); }
The call write(1, i--, 1)
writes 1 character from i
to file descriptor 1 (stdout). And the postdecrement is superfluous because this i
is a local variable never referenced again. So this function is equivalent to putchar(*i)
.
Inlining the read2
function within the main loop gives
#include <stdio.h> int i = 0; int main() { while (i != 14) { putchar(*(i++ + "hello, world!\n")); } return 0; }
for which the meaning is obvious.
Not in a mind of taking this apart completely, but there are some hints:
'-' - '-'
is obfuscated for 0
'/' / '/'
and the i / i
in read() are obfuscated for 1
Remember that [] is commutative, i.e. i["]<i;++i){--i;}"]
is the same as "]<i;++i){--i;}"[i]
(having a char array and pointing at the i'th element of it). The content of the string doesn't matter in any way, only its length is used to define the number of iterations of the loop. Any other string of the same length (incidentially, the same length as the output...) would work. After that number of iterations, "string"[i] returns the null character that terminates the string. Zero == false, loop terminates.
With that, it should be comparatively easy to figure out the rest.
Edit: The upvotes made me interested enough to look at this some more.
Of course, i++ + "Hello, world!\n"
is the same as "Hello, world!\n"[ i++ ]
.
codelark already pointed out that 0
is the fid for stdout. (Give him +1 for that, not me. Just mentioning it for completeness.)
The i
in read()
is of course local, i.e. the i--
in read()
does not affect the i
in main()
. Since the following i / i
is always 1
anyway, the --
operator does nothing at all.
Oh, and tell the interviewer to fire whoever wrote this code. It does not do error checking on the return value of write()
. I can live with notoriously badly-written code (and have, for many years), but not checking for errors is worse than bad, that's faulty. :-)
The rest is just some third-grade maths. I'd pass that to an intern. ;-)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With