151

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); } 
11
  • 1
    Are you compiling as C or as C++? What errors do you see? You cannot call main in C++. Commented Oct 29, 2011 at 10:05
  • @ninjalj I have created a C++ project and copy/past the code the error are : illegal, left operand has type 'void (__cdecl *)(int)' and expression must be a pointer to a complete object type Commented Oct 29, 2011 at 10:15
  • 1
    @ninjalj These code is working on ideone.org but not in visual studio ideone.com/MtJ1M Commented Oct 29, 2011 at 10:27
  • @oussama Similar, but slightly more difficult to understand: ideone.com/2ItXm You're welcome. :) Commented Oct 29, 2011 at 12:30
  • 2
    i have removed all '&' characters from these line (&main + (&exit - &main)*(j/1000))(j+1); and this code still works. Commented Oct 30, 2011 at 16:57

3 Answers 3

266

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).

Sign up to request clarification or add additional context in comments.

21 Comments

foo(arg) and (&foo)(arg) are equivalent, they call foo with argument arg. newty.de/fpt/fpt.html is an interesting page about function pointers.
@Krishnabhadra: in the first case, foo is a pointer, &foo is the address of that pointer. In the second case, foo is an array, and &foo is equivalent to foo.
Unnecessarily complex, at least for C99: ((void(*[])()){main, exit})[j / 1000](j + 1);
&foo is not the same as foo when it comes to an array. &foo is a pointer to the array, foo is a pointer to the first element. They do have the same value though. For functions, fun and &fun are both pointers to the function.
FYI, if you look at the relevant answer to the other question cited above, you'll see there's a variation that is in fact comformant C99. Scary, but true.
|
41

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).

3 Comments

Good answer, but one doubt..How main exit with exit code 1001? Main is not returning anything..Any default return value?
When j reaches 1000, main doesn't recurse into itself anymore; instead, it calls the libc function exit, which takes the exit code as its argument and, well, exits the current process. At that point, j is 1000, so j+1 equals 1001, which becomes the exit code.
Actually the exit code will be 233 (1001 % 256 or 1001 & 255).
0

https://stackoverflow.com/a/7937813/6607497 explains it all, but for the impatient here is the equivalent (readable) code:

#include <stdio.h> #include <stdlib.h> void main(int j) { printf("%d\n", j); if (i/1000 == 0) main(j+1); else exit(j+1); } 

So i guess its obvious how it works. The only real trick being used is the "computed goto" (&main + (&exit - &main)*(j/1000)), evaluating to either main while j/1000 is zero, or exit otherwise (actually if it's 1).

Maybe also note that the program is misusing argc as j, so it will count differently when you pass arguments to the program, and it will most likely crash when you add more than 2000 parameters...

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.