Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why are both these function pointers legal in C/C++?

I have these two test functions:

int apply_a(int (*fun)(int, int), int m, int n) {
    return (*fun)(m,n);
}

int apply_b(int (*fun)(int, int), int m, int n) {
    return fun(m,n);
}

they appear to return something different, so why do both of them yield the same result?

int add(int a, int b) {return a + b;}

int res_a = apply_a(add, 2, 3); // returns 5
int res_b = apply_b(add, 2, 3); // returns 5

I would've assumed that one of them would return the pointer address or the pointer itself; rather than the value stored on the pointer...

So why is it doing this?

like image 947
Electric Coffee Avatar asked Oct 27 '13 11:10

Electric Coffee


3 Answers

Because C++ offers syntactic sugar when it comes to handling the address of non-member functions and using pointers to them.

One can get address of such function:

int someFunc(int);

with either:

int (* someFuncPtr)(int) = someFunc;

or:

int (* someFuncPtr)(int) = &someFunc;

There is also syntactic sugar for using such pointer, either call pointed-to function with:

(*someFuncPtr)(5);

or with simplified syntax:

someFuncPtr(5);
like image 192
altariste Avatar answered Sep 21 '22 14:09

altariste


(*fun)(m,n) is the same as fun(m,n) due to rules in C and C++ that convert functions to pointers to functions.

In C 2011, the rule is clause 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, the _Alignof 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”. In C++, the rule is clause 4.3.

Note that a function designator is not merely an identifier that names a function. It could be an identifier, or it could be another expression. For example, if foo is the name of a function, it is automatically converted to a pointer to a function by the above. Then, since foo is a pointer to the function, *foo is the function. This means you can write:

(*fun)(m,n)

The result is that fun is automatically converted to a pointer, then * evaluates to the function, then *fun is converted back to a pointer, then the function is called. You can continue this and write:

(**************fun)(m,n)

This is the same as fun(m,n). Each * produces the function again, but the compiler automatically converts it back to a pointer. You can continue this battle forever, but the compiler will always win.

In fact, these all have the same effect:

(&fun)(m,n)
( fun)(m,n)
(*fun)(m,n)
like image 27
Eric Postpischil Avatar answered Sep 18 '22 14:09

Eric Postpischil


It is because you are not returning memory addresses of these values. Calling a function with pointer does not change it's value it's still calling the function. What you can do is return a value to a variable and then get it's memory address such as:

int result = fun(m,n);
cout << "the result " << result << " pointing at " << &result << endl;
like image 38
Sarp Kaya Avatar answered Sep 21 '22 14:09

Sarp Kaya