C中的函数指针和内存地址

function pointer and memory address in C

在下面的程序中,&foo*foofoo指向同一个内存地址:

#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

有谁能解释一下吗? 谢谢。

在 C 标准的术语中,任何具有函数类型的表达式都是 函数指示符。因此,当用作表达式时,函数的名称是函数指示符。

除了获取其地址外,您无法对函数指示符执行​​任何操作。您不能将数字添加到功能指示符,也不能将其与另一个功能指示符进行比较,等等。当然,你可以调用一个函数,但这实际上是通过地址来完成的,而不是通过指示符,我稍后会解释。由于除了获取函数的地址之外,您无法对函数执行任何操作,因此 C 会自动为您完成此操作。根据 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".

结果是:

  • &foo中,&foo的地址,所以&foofoo的地址。
  • foo中,函数标志符自动转换为函数地址,所以foo&foo
  • *foo中,函数标识符自动转换为函数地址。然后 * 运算符将其转换回函数,从而生成函数指示符。然后自动转换再次发生,函数指示符被转换回函数的地址,所以*foo的结果是&foo

当您调用函数时,使用 function ( argument-list... ) 表示法,function 实际上必须是指向函数的指针。因此,您可以使用 (&foo)(arguments...) 调用 foo。自动转换简化了语法,所以你可以写成 foo(arguments...),但调用表达式实际上需要函数的地址,而不是函数指示符。

顺便提一句:

  • size_t 值的正确 printf 说明符是 %zx,而不是 %lx
  • 如果您包含 <stdint.h>,它定义了一个用于将指针转换为整数的类型,uintptr_t。这最好是将指针转换为 size_t.

函数 foo 可隐式转换为指向函数 foo 的指针。

应用于函数的一元 & 产生指向函数的指针,就像它应用于变量时产生变量的地址一样。

应用于函数指针的一元*产生指向的函数,就像它应用于指向变量的普通指针时产生指向的变量一样。

所以在这里,foo&foo 相同,后者与 *foo 相同。

因此 *foo*(&foo) 相同,后者与 foo 相同。