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

时间:2019-03-28 11:41:58

标签: 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;
}

输出为:

arg = 0
arg = 0
arg = 0
&foo = 55eeef54c720
foo = 55eeef54c720
*foo = 55eeef54c720

有人可以解释吗? 谢谢。

2 个答案:

答案 0 :(得分:5)

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

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

  

除非它是sizeof运算符或一元&运算符的操作数,否则类型为“ function returning type”的函数指示符将转换为类型为“ pointer to function”的表达式返回类型”。

其结果是:

  • &foo中,&的地址为foo,因此&foofoo的地址。
  • 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相同。