39

Here is a code that purpose is to set the program counter to jump to address 0x1000. I know what it does but I don't understand how. It is related to my lack of C language knowledge. May be you can enlighten me. Here is the statement/function (I even don't know what it is :))

((void (*)())0x1000)();

I thing it is pointer to a functions that returns void and accepts no argument. Please correct me if I am wrong.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
Radoslaw Krasimirow
  • 1,833
  • 2
  • 18
  • 28
  • What's the platform and CPU where you'll run this code? – Sir Jo Black May 20 '15 at 09:25
  • 8
    This statement may be used, if your try to call a procedure with a well-known fixed address, f.e. a BIOS procedure. In old IBM PC you could call `(void (*far)())0xFFFFFFF0ul`. This procedure restarts the PC. – Mark Shevchenko May 20 '15 at 09:27
  • 8
    I feel like this has a side meaning of "F**k you" when you find it in code you're supposed to maintain. Then again, as a non-C dev, all C looks like an incomprehensible mess to me, so I could well be dead wrong. – Nic May 20 '15 at 11:24
  • cdecl can't quite explain this one, but [with minor modifications](http://cdecl.ridiculousfish.com/?q=explain+%28void+%28*%29%28%29%29foo) it spits out a perfectly readable English description. – Kevin May 20 '15 at 16:04
  • 1
    @QPaysTaxes once you get a little bit used to the C/C++ (member) function pointer notation then it is actually fairly easy to read that. However still casting a literal to a function pointer and call it is quite a "WTF" operation... unless you are writing beyond an OS. – DarioP May 20 '15 at 16:10
  • just a fact: this exact code is used in TI's MSP430 series controllers to jump to BSL(Bootstrap loader) location i've seen and used it in the 5xx and the 2xx series. – Koushik Shetty May 25 '15 at 14:13

4 Answers4

48

C declarations are decoded from inside out using a simple rule: start from the identifier and check on the right side for [] (array) or () (function) then check on the left side for the type of the values (stored in the array or returned by the function), without crossing the parentheses; escape from the parentheses and repeat.

For example:

void (*p)()

p is (nothing on the right) a pointer (on the left, don't cross the parentheses) to (escape the parentheses, read the next level) a function (right) that returns nothing (left).

When the identifier (p in this case) is missing, all that remains is a type declaration.

A type enclosed in parentheses, put in front of a value is a type cast.

(void (*)())0x1000

converts the number 0x1000 to a pointer to a function that doesn't return anything (see what's outside the parentheses in the paragraph about the declaration of p above).

On the next level, the expression above (a pointer to a function can be used in the same way as a function name) is used to execute the code pointed at.

See below the entire expression de-composed:

(
  (
    void (*)()   /* type: pointer to function that doesn't return anything     */
  )0x1000        /* value 0x1000 treated as a value of the type declared above */
)                /* enclose in parentheses to specify the order of evaluation  */ 
();              /* the pointer above used as a function name to run the code  */
axiac
  • 68,258
  • 9
  • 99
  • 134
18

(void (*)()) is a pointer to a function returning void and taking an unspecified, but fixed, number of arguments.

(void (*)())0x1000 is casting the literal 0x1000 to the above type.

Finally, the suffixed () calls that function. The expression preceding that needs to be in brackets otherwise the suffixed () will bind to the 0x1000 which is not syntactically valid.

It's down to you to check if the casting is actually valid. If not then the behaviour of your program is undefined.

Bathsheba
  • 231,907
  • 34
  • 361
  • 483
  • 1
    Not quite right. Also `void (*)()` is a pointer, but it's not a valid declaration statement in some cases, because of the missing identifier for that pointer. This declaration is valid: `void call_a_ptr(void(*)());` - it declares a function that takes a pointer to a function which returns void and takes no arguments. – Wolf May 20 '15 at 09:35
13

A constant

0x1000

gets cast to a type:

(type)0x1000

The type is void (*)() — a pointer (asterisk) to a function which takes no (oops, see the comment by pmg) unspecified number of parameters (empty parentheses on the right) and returns no value (void on the left). Additional parens on the asterisk prevent associating it to void, which would incorrectly create a void * type here.

So after the cast you have a pointer to a parameter-less void function at the addres 0x1000:

(void (*)())0x1000

And that function...

((void (*)())0x1000)

gets called by adding an empty parameters list:

((void (*)())0x1000)()

Finally, the semicolon added at the end transforms this function-call expression into a complete instruction:

((void (*)())0x1000)();
CiaPan
  • 9,381
  • 2
  • 21
  • 35
6

The person who wrote that code should have rewritten it in a readable manner as:

#define ADDRESS_OF_FUNCTION_X 0x1000

typedef void (*func_ptr_t)(void);

...

func_ptr_t function_x = (func_ptr_t)ADDRESS_OF_FUNCTION_X;
function_x();

What the code does is now pretty much self-documented.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • 2
    Yes, but this doesn't explain why the other syntax does what it does. – Arturo Torres Sánchez May 20 '15 at 14:10
  • @ArturoTorresSánchez If you cast an integer to a function pointer, the integer will turn into the address of a function. Just like any other integer to pointer cast will turn an integer into an address. And then you call that function. What else is there to explain? I assume the OP is already familiar with how pointers work. This is not really complex code, the original was just a bit unreadable. – Lundin May 20 '15 at 14:50