Issue
In the following program, &foo
, *foo
and foo
points to the same memory adress :
#include <stdio.h>
int foo(int arg)
{
printf("arg = %d\n", arg);
return arg;
}
int main()
{
foo(0); // ok
(*foo)(0); // ok
(&foo)(0); // ok
printf("&foo = %lx\n", (size_t)(&foo));
printf("foo = %lx\n", (size_t)(foo));
printf("*foo = %lx\n", (size_t)(*foo));
return 0;
}
the output is :
arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720
Does anyone can explain this ? Thank you.
Solution
In the terminology of the C standard, any expression that has function type is a function designator. So, when used as an expression, the name of a function is a function designator.
There is nothing you can do with a function designator except take its address. You cannot add a number to a function designator, you cannot compare it to another function designator, and so on. Of course, you can call a function, but this is actually done by address, not by designator, as I will explain in a moment. Since there is nothing you can do with a function except take its address, C does this for you automatically. Per C 2018 6.3.2.1 4:
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".
The result of this is:
- In
&foo
, the&
takes the address offoo
, so&foo
is the address offoo
. - In
foo
, the function designator is automatically converted to the address of the function, sofoo
is&foo
. - In
*foo
, the function designator is automatically converted to the address of the function. Then the*
operator converts this back to the function, which produces a function designator. Then the automatic conversion happens again, and the function designator is converted back to the address of the function, so the result of*foo
is&foo
.
When you call a function, using the function ( argument-list... )
notation, the function
must actually be a pointer to a function. Thus, you can call foo
using (&foo)(arguments...)
. The automatic conversion simplifies the syntax so you can write foo(arguments...)
, but the call expression actually requires the address of the function, not the function designator.
Incidentally:
- A proper
printf
specifier forsize_t
values is%zx
, not%lx
. - If you include
<stdint.h>
, it defines a type intended for converting pointers to integers,uintptr_t
. This is preferably to converting pointers tosize_t
.
Answered By - Eric Postpischil