I've found C
code that prints from 1 to 1000 without loops or conditionals :
But I don't understand how it works. Can anyone go through the code and explain each line?
#include <stdio.h>
#include <stdlib.h>
void main(int j) {
printf("%d\n", j);
(&main + (&exit - &main)*(j/1000))(j+1);
}
It uses recursion, pointer arithmetic, and exploits the rounding behavior of integer division.
The
j/1000
term rounds down to 0 for allj < 1000
; oncej
reaches 1000, it evaluates to 1.Now if you have
a + (b - a) * n
, wheren
is either 0 or 1, you end up witha
ifn == 0
, andb
ifn == 1
. Using&main
(the address ofmain()
) and&exit
fora
andb
, the term(&main + (&exit - &main) * (j/1000))
returns&main
whenj
is below 1000,&exit
otherwise. The resulting function pointer is then fed the argumentj+1
.This whole construct results in recursive behavior: while
j
is below 1000,main
calls itself recursively; whenj
reaches 1000, it callsexit
instead, making the program exit with exit code 1001 (which is kind of dirty, but works).Don't ever write code like that.
For
j<1000
,j/1000
is zero (integer division). So:is equivalent to:
Which is:
Which calls
main
withj+1
.If
j == 1000
, then the same lines comes out as:Which boils down to
Which is
exit(j+1)
and leaves the program.(&exit)(j+1)
andexit(j+1)
are essentially the same thing - quoting C99 §6.3.2.1/4:exit
is a function designator. Even without the unary&
address-of operator, it is treated as a pointer to function. (The&
just makes it explicit.)And function calls are described in §6.5.2.2/1 and following:
So
exit(j+1)
works because of the automatic conversion of the function type to a pointer-to-function type, and(&exit)(j+1)
works as well with an explicit conversion to a pointer-to-function type.That being said, the above code is not conforming (
main
takes either two arguments or none at all), and&exit - &main
is, I believe, undefined according to §6.5.6/9:The addition
(&main + ...)
would be valid in itself, and could be used, if the quantity added was zero, since §6.5.6/7 says:So adding zero to
&main
would be ok (but not much use).