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

Sca*_*cab 2 c linux gcc function-pointers

在以下程序中&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;
}
Run Code Online (Sandbox Code Playgroud)

输出为:

arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720
Run Code Online (Sandbox Code Playgroud)

有人可以解释吗?谢谢。

Eri*_*hil 5

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

除了指定地址外,您不能使用功能指示符进行任何操作。您不能将数字添加到功能指示符,也不能将其与另一个功能指示符进行比较,依此类推。当然,您可以调用一个函数,但这实际上是通过地址而不是通过指定符来完成的,正如我稍后会解释的那样。由于除了获取其地址外,您无法使用其他任何功能,因此C会自动为您执行此操作。根据C 2018 6.3.2.1 4:

除非是运算sizeof符或一元运算&符的操作数,否则将类型为“函数返回类型”的函数指定符转换为具有类型为“函数返回类型的指针”的表达式。

结果是:

  • 在中&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