How come pointer to a function be called without dereferencing?
Asked Answered
C

5

2

I have a weird typedef statement in a C++ program, generated by Py++.

double radius(int);  // function to be wrapped
typedef double (*radius_function_type)(int);    
bp::def("radius", radius_function_type(&radius));   // bp::def is a function for wrapping

What I figured out so far is that the above typedef statemnt is not of the type, most of us are familiar with,

typedef complex_type simple_alias;

Rather it is a way to declare pointer to a function which takes int as argument and returns double (same as the prototype). So my question now is that, how come pointer to a function (without dereferencing) be called with address of a function as an argument? This also doesn't match with the prototype. Somebody please explain!

Catalog answered 3/6, 2009 at 12:35 Comment(0)
L
3

Your question is confusing. Are you asking what this does:

radius_function_type(&radius)"

This is just a C++ typecast, a bit like:

radius (int (42));

but since radius is already of type radius_function_type then you can just as easily do:

bp::def("radius", radius);

but as this is code generated by Py++, it's probably being extra careful with the output.

Lodie answered 3/6, 2009 at 12:51 Comment(4)
more like a C style typecast, actually. C++ has static_cast, dynamic_cast, etc.Zebu
Also note (I think) that the reason for this cast syntax is for compatibility with constructors (in template code, especially). So MyClass(0) calls a 1-arg constructor of MyClass, float(0) is the same value as 0.0, and radius_function_type(0) casts the null pointer to double(*)(int). float(0), my_type(0) are synonymous with (float) 0, (my_type) 0.Seethrough
It's in fact not a C style typecast. C uses exclusively the form (TYPE) EXPR. In C++, you can also use TYPE(EXPR). The previous comment correctly notes that this is the ctor form of casting, and ctors are obviously unique to C++.Orford
To be fair to crashmstr, it is "like" a C-style cast, in the sense that 5.2.3 of the C++ spec says that it's equivalent. Given that it does exactly the same thing, but the C++ spec has different names for it (function-notation as opposed to cast expression), neither of which is "C-style cast" I'm not sure exactly what we're entitled to call a C-style cast...Seethrough
S
5

It doesn't declare a function pointer variable but a function pointer typedef called radius_function_type. radius_function_type(&radius) is just a (redundant) cast for the function pointer itself. (The unary & address-of operator is also redundant; for a function, radius and &radius are the same thing.)

On a low level, calling a function is just placing the arguments somewhere according to the underlying calling convention (usually on the stack) and then jumping to a memory address. So the compiler can call a function with just a pointer if it knows the function pointer type (function signature) and the pointer value itself.

Starnes answered 3/6, 2009 at 12:47 Comment(0)
B
3

Well ... It is a bit similar to how arrays are related to pointers, in C and C++. The name of a function is basically a pointer, too. Seen from that perspective, it's not too surprising that given a definition:

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

You can do the call either directly, through the pointer that is the function's name:

foo(1, 2);

or by storing that value in a separate variable, which must be declared as a pointer:

int (*pointer)(int, int) = foo;
pointer(1, 2);

In this case, we can call through the pointer variable directly, and there's also no need to explicitly "take the address of" the function by writing &foo.

Bagwig answered 3/6, 2009 at 12:38 Comment(2)
I very much appreciate your prompt reply. But what is still un-explained is that the argument in radius_function_type(&radius) is the address of a function, which doesn't match the prototype. Please throw some light on this issue!Catalog
@Aamir: &radius and radius both act as pointers to the function. Since functions are not first-class objects in C++, there's no way to use a function other than through a pointer to it, and so the language just lets you do whichever you want. This behaviour for function names is in contrast with variables: if you globally declare an integer my_int, then my_int and &my_int are totally different things.Seethrough
L
3

Your question is confusing. Are you asking what this does:

radius_function_type(&radius)"

This is just a C++ typecast, a bit like:

radius (int (42));

but since radius is already of type radius_function_type then you can just as easily do:

bp::def("radius", radius);

but as this is code generated by Py++, it's probably being extra careful with the output.

Lodie answered 3/6, 2009 at 12:51 Comment(4)
more like a C style typecast, actually. C++ has static_cast, dynamic_cast, etc.Zebu
Also note (I think) that the reason for this cast syntax is for compatibility with constructors (in template code, especially). So MyClass(0) calls a 1-arg constructor of MyClass, float(0) is the same value as 0.0, and radius_function_type(0) casts the null pointer to double(*)(int). float(0), my_type(0) are synonymous with (float) 0, (my_type) 0.Seethrough
It's in fact not a C style typecast. C uses exclusively the form (TYPE) EXPR. In C++, you can also use TYPE(EXPR). The previous comment correctly notes that this is the ctor form of casting, and ctors are obviously unique to C++.Orford
To be fair to crashmstr, it is "like" a C-style cast, in the sense that 5.2.3 of the C++ spec says that it's equivalent. Given that it does exactly the same thing, but the C++ spec has different names for it (function-notation as opposed to cast expression), neither of which is "C-style cast" I'm not sure exactly what we're entitled to call a C-style cast...Seethrough
F
1

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.

Frigorific answered 3/6, 2009 at 12:46 Comment(0)
H
1

Function pointer is basically the address of the function that needs to be invoked. To call the function pointed to by a function pointer, you consider the function pointer as though it were the name of the function that you wish to call. The act of calling it itself performs the dereference; there is no need for explicit dereference.

Function pointer syntax can look like pointers (with & and *) or that can be omitted as well. As @unwind already pointed out it is similar to how arrays are treated where bare array is similar to pointer and optionally you can prefix the array with & to get the address.

Hamiltonian answered 3/6, 2009 at 12:55 Comment(1)
You make a common mistake about arrays: given 'int n[100]', &n isn't the same as n (n is convertible to int*, &n isn't)Rooster

© 2022 - 2024 — McMap. All rights reserved.