【问题标题】:function pointer and memory address in C [duplicate]C中的函数指针和内存地址[重复]
【发布时间】:2019-08-19 04:09:47
【问题描述】:

在以下程序中,&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

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

【问题讨论】:

  • 函数名(一个符号)实际上是一个内存地址。链接可执行文件时,喜欢使用内存地址更改函数名称。像call foo这样的CPU指令是跳转到foo函数CPU机构(代码)所在的RAM块。

标签: c linux gcc function-pointers


【解决方案1】:

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

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

除非它是sizeof 运算符的操作数,或一元&amp; 运算符,类型为“函数返回类型”的函数指示符将转换为类型为“指向函数返回类型的指针”的表达式。

这样的结果是:

  • &amp;foo中,&amp;foo的地址,所以&amp;foo就是foo的地址。
  • foo中,函数指示符会自动转换为函数的地址,所以foo就是&amp;foo
  • *foo 中,函数指示符会自动转换为函数的地址。然后* 运算符将其转换回函数,从而产生一个函数指示符。然后再次发生自动转换,函数指示符被转换回函数的地址,所以*foo的结果是&amp;foo

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

顺便说一句:

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

【讨论】:

    【解决方案2】:

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

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

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

    所以这里,foo&amp;foo 相同,与*foo 相同。

    所以*foo*(&amp;foo) 相同,与foo 相同。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-04-07
      • 1970-01-01
      • 2020-08-15
      • 1970-01-01
      • 1970-01-01
      • 2020-12-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多