views:

476

answers:

4

Why and how does dereferencing a function pointer just "do nothing"?

This is what I am talking about:

#include<stdio.h>

void hello() { printf("hello"); }

int main(void) { 
    (*****hello)(); 
}

From a comment over here:

function pointers dereference just fine, but the resulting function designator will be immediately converted back to a function pointer


And from an answer here:

Dereferencing (in way you think) a function's pointer means: accessing a CODE memory as it would be a DATA memory.

Function pointer isn't suppose to be dereferenced in that way. Instead, it is called.

I would use a name "dereference" side by side with "call". It's OK.

Anyway: C is designed in such a way that both function name identifier as well as variable holding function's pointer mean the same: address to CODE memory. And it allows to jump to that memory by using call () syntax either on an identifier or variable.


How exactly does dereferencing of a function pointer work?

+8  A: 
Norman Ramsey
@Potato thanks for the comment. I'm not qualified to explain C++ and have amended my answer to make clear that it's for C only.
Norman Ramsey
+3  A: 

C++03 §4.3/1:

An lvalue of function type T can be converted to an rvalue of type “pointer to T.” The result is a pointer to the function.

If you attempt an invalid operation on a function reference, such as the unary * operator, the first thing the language tries is a standard conversion. It's just like converting an int when adding it to a float. Using * on a function reference causes the language to take its pointer instead, which in your example, is square 1.

Another case where this applies is when assigning a function pointer.

void f() {
    void (*recurse)() = f; // "f" is a reference; implicitly convert to ptr.
    recurse(); // call operator is defined for pointers
}

Note that this doesn't work the other way.

void f() {
    void (&recurse)() = &f; // "&f" is a pointer; ERROR can't convert to ref.
    recurse(); // OK - call operator is *separately* defined for references
}

Function reference variables are nice because they (in theory, I've never tested) hint to the compiler that an indirect branch may be unnecessary, if initialized in an enclosing scope.

In C99, dereferencing a function pointer yields a function designator. §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’’.

This is more like Norman's answer, but notably C99 has no concept of rvalues.

Potatoswatter
+1  A: 

Put yourself in the shoes of the compiler writer. A function pointer has a well defined meaning, it is a pointer to a blob of bytes that represent machine code.

What do you do when the programmer dereferences a function pointer? Do you take the first (or 8) bytes of the machine code and reinterpret that as a pointer? Odds are about 2 billion to one that this won't work. Do you declare UB? Plenty of that going around already. Or do you just ignore the attempt? You know the answer.

Hans Passant
A: 

How exactly does dereferencing of a function pointer work?

Two steps. The first step is at compile time, the second at runtime.

In step one, the compiler sees it has a pointer and a context in which that pointer is dereferenced (such as (*pFoo)() ) so it generates code for that situation, code that will be used in step 2.

In step 2, at runtime the code is executed. The pointer contains some bytes indicating which function should be executed next. These bytes are somehow loaded into the CPU. A common case is a CPU with an explicit CALL [register] instruction. On such systems, a function pointer can be simply the address of a function in memory, and the derefencing code does nothing more than loading that address into a register followed by a CALL [register] instruction.

MSalters