在以下程序中,&foo
,*foo
和foo
指向相同的内存地址:
#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;
}
输出为:
arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720
有人可以解释吗? 谢谢。
答案 0 :(得分:5)
在C标准的术语中,任何具有函数类型的表达式都是函数指示符。因此,当用作表达式时,函数的名称就是函数指示符。
除了指定地址外,您不能使用功能指示符进行任何操作。您不能将数字添加到功能指示符,也不能将其与另一个功能指示符进行比较,依此类推。当然,您可以调用一个函数,但这实际上是通过地址而不是通过指定符完成的,正如我稍后会解释的那样。由于除了函数的地址外,您无法执行其他任何操作,因此C会自动为您执行此操作。 Per C 2018 6.3.2.1 4:
除非它是
sizeof
运算符或一元&
运算符的操作数,否则类型为“ function returning type”的函数指示符将转换为类型为“ pointer to function”的表达式返回类型”。
其结果是:
&foo
中,&
的地址为foo
,因此&foo
是foo
的地址。foo
中,函数指示符自动转换为函数的地址,因此foo
为&foo
。*foo
中,功能指示符自动转换为功能的地址。然后*
运算符将其转换回函数,从而产生一个函数指示符。然后再次发生自动转换,并且功能指示符被转换回该函数的地址,因此*foo
的结果为&foo
。调用函数时,使用function ( argument-list... )
表示法,function
实际上必须是指向函数的指针。因此,您可以使用foo
来调用(&foo)(arguments...)
。自动转换简化了语法,因此您可以编写foo(arguments...)
,但是调用表达式实际上需要函数的地址,而不是函数指定符。
偶然地:
printf
值的正确size_t
指定符是%zx
,而不是%lx
。<stdint.h>
,则它将定义用于将指针转换为整数uintptr_t
的类型。最好是将指针转换为size_t
。答案 1 :(得分:3)
函数foo
可隐式转换为指向函数foo
的指针。
应用于函数的一元&
会产生指向该函数的指针,就像应用于变量时会产生变量的地址一样。
应用于函数指针的一元*
会生成指向函数,就像将其应用于指向变量的普通指针时会生成指向变量一样。
因此,foo
与&foo
相同,而*foo
也相同。
所以*foo
与*(&foo)
相同,与foo
相同。