How does the C code that prints from 1 to 1000 without loops or conditional statements work?
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);
}
Solution 1:
Don't ever write code like that.
For j<1000
, j/1000
is zero (integer division). So:
(&main + (&exit - &main)*(j/1000))(j+1);
is equivalent to:
(&main + (&exit - &main)*0)(j+1);
Which is:
(&main)(j+1);
Which calls main
with j+1
.
If j == 1000
, then the same lines comes out as:
(&main + (&exit - &main)*1)(j+1);
Which boils down to
(&exit)(j+1);
Which is exit(j+1)
and leaves the program.
(&exit)(j+1)
and exit(j+1)
are essentially the same thing - quoting C99 §6.3.2.1/4:
A function designator is an expression that has function type. Except when it is the operand of the sizeof operator or the unary & operator, a function designator with type "function returning type" is converted to an expression that has type "pointer to function returning type".
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:
The expression that denotes the called function shall have type pointer to function returning void or returning an object type other than an array type.
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:
When two pointers are subtracted, both shall point to elements of the same array object, or one past the last element of the array object; ...
The addition (&main + ...)
would be valid in itself, and could be used, if the quantity added was zero, since §6.5.6/7 says:
For the purposes of these operators, a pointer to an object that is not an element of an array behaves the same as a pointer to the first element of an array of length one with the type of the object as its element type.
So adding zero to &main
would be ok (but not much use).
Solution 2:
It uses recursion, pointer arithmetic, and exploits the rounding behavior of integer division.
The j/1000
term rounds down to 0 for all j < 1000
; once j
reaches 1000, it evaluates to 1.
Now if you have a + (b - a) * n
, where n
is either 0 or 1, you end up with a
if n == 0
, and b
if n == 1
. Using &main
(the address of main()
) and &exit
for a
and b
, the term (&main + (&exit - &main) * (j/1000))
returns &main
when j
is below 1000, &exit
otherwise. The resulting function pointer is then fed the argument j+1
.
This whole construct results in recursive behavior: while j
is below 1000, main
calls itself recursively; when j
reaches 1000, it calls exit
instead, making the program exit with exit code 1001 (which is kind of dirty, but works).