autistic456
autistic456

Reputation: 183

Why does function pointer in c does not have to be pointer at all?

Having this:

#include <stdio.h>
#include <stdlib.h>

int do_op(int (*op)(int,int),int a, int b){ return op(a,b); }
/*int do_op(int (op)(int,int),int a,int b){return op(a,b);} */
int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }

int main(){
    printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));
}

From what I know about function pointer so far, is their "type" is of return value's type. (Does not know how it is implemented in gas, wheter the return value is in %rax before ret? just an detail), however what is the point of a reference to a function, when it does not have to be reference at all? What does it mean, when it is not pointer? (like (op)), is then the function used by value (not address)? But function in general does not have value, it has only start address in %rbi and after it finishes, it is retuned back to upper function by ret, so what does it mean in c, a function "pointer" is not pointer? (give some examples please)

The question is relating to the comment in the code, where the (op) part is not a pointer, but still work. So is it a pointer or not?

Upvotes: 0

Views: 1145

Answers (5)

Vlad from Moscow
Vlad from Moscow

Reputation: 311088

From what I know about function pointer so far, is their "type" is of return value's type.

From the C Standard (6.2.5 Types)

A function type is characterized by its return type and the number and types of its parameters.

For example the type of these functions

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

is int( int, int ). That is to describe a function you have to specify what it accepts and what it returns.

What does it mean, when it is not pointer? (like (op))

In this declaration

int do_op(int (op)(int,int),int a,int b){return op(a,b);}

the parameter op has the type int( int, int ). The compiler adjusts a parameter having a function type to a parameter having the type of pointer to the function.

So for example these two declarations

int do_op(int (op)(int,int),int a,int b);
int do_op(int (*op)(int,int),int a,int b);

that can be rewritten without parameter names like

int do_op(int (int,int),int ,int );
int do_op(int (*)(int,int),int ,int );

are equivalent and declare the same one function. You may include the both declarations in your program though the compiler can issue a warning that there are redundant declarations.

From the C Standard (6.7.6.3 Function declarators (including prototypes))

8 A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.

When a function is used as an argument like in this statement

printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));

then it is implicitly converted to pointer to the function. The value of the pointer is the entry point of the function where the control can be passed.

From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)

4 A function designator is an expression that has function type. Except when it is the operand of the sizeof operator65) 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’’.

Upvotes: 1

John Bollinger
John Bollinger

Reputation: 181169

From what I know about function pointer so far, is their "type" is of return value's type.

No. I know we've addressed this issue in comments and answers to some of your previous questions. The type of a function pointer is different from the pointed-to function's return type, and also different from a pointer to the function's return type. The type of a function pointer is a particular function pointer type. All function pointer types have a return type as one of their attributes. They also convey information about the number and type of the function's parameters. Function pointer type names also differ from all object pointer type names. In the present case, the type name is int (*)(int,int), which I'm sure you see is different from both int and int *.

what is the point of a reference to a function, when it does not have to be reference at all?

The reason for using a function pointer (not "reference") is to allow different actual functions to be selected at runtime. In your case, different calls to function do_op() can be made to perform different operations. That's no big deal in the example, because do_op() does nothing but call the specified function one time, and the choice of operation is hardcoded into each call, but it would be more interesting if, say, the choice of operation were dictated by user input.

And of course the argument corresponding to the function pointer parameter has to be a (compatible) function pointer. C does not make any exception to its type matching rules in such cases.

What does it mean, when it is not pointer? (like (op)),

But it is a pointer. Wherever an expression of function type appears in a valid C expression, other than as the operand of a unary & operator, it is automatically converted to a pointer to the function it identifies. That applies to the identifier of the function being called, too: the function-call operator, (), is an operator on function pointers. You can regard this as a convenience feature: you do not need to use the & operator to obtain a a function pointer. This makes code a bit easier to write and read. C does not provide any way to express accessing a function value.

The question is relating to the comment in the code, where the (op) part is not a pointer, but still work. So is it a pointer or not?

Parameter op of function do_op() is a pointer to a function that expects two arguments of type int and returns an int. In each call to that function, the corresponding argument is a function identifier. As expressions of function type, these are automatically converted to pointers. The resulting function pointers are of the expected type.

Upvotes: 2

dbush
dbush

Reputation: 224677

The type of a function pointer is not its return type. It is the type of the function pointed to.

In the case of the parameter int (*op)(int,int), the type of op is "pointer to function which takes an int and an int, and returns int".

You could also define the parameter as int op(int,int) in which case the type of op is "function which takes an int and an int, and returns int".

Because function pointers point to code, they don't have a "value" in the sense that objects do. In fact, anyplace you specify an expression with a function type it is automatically converted to a pointer to a function. So you can declare the parameter op as int (*op)(int,int) or int op(int,int) and they will be exactly the same.

Section 6.3.2.1p4 of the C standard says the following regarding function types:

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

Section 6.7.6.3p8 also says the following regarding a function type as a parameter:

A declaration of a parameter as ‘‘function returning type’’ shall be adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.

It is because of this that a parameter of function type is allowed. A variable of function type that is not a parameter is not useful because it can't be initialized or assigned.

Upvotes: 3

Daniel
Daniel

Reputation: 31589

A function pointer in c is always a pointer to the first instruction of the function.
A function value in c (the value of applying * to a function pointer) is also implemented the same as a function pointer, leading to this confusion.
In the end functions will always be pointers to code and the compiler is just ignoring whether you used a c function pointer or value.

Upvotes: 0

torrey1028
torrey1028

Reputation: 19

Function pointers differ from data pointers in that they point to code, not to data. So the value of the pointer is going to be the memory location for the beginning on the function. Since the value is already and address in memory, there is no reason to deference it like we would a normal pointer.

This article seems to have a clear explanation of the concept with good examples if you want more details: Function Pointers in C - GeeksforGeeks

Upvotes: 0

Related Questions