【问题标题】:Taking the address of a function from within that function从函数中获取函数的地址
【发布时间】:2017-12-07 14:49:38
【问题描述】:

首先,问题是:你有什么理由不能从函数中获取函数的地址?

#include <stdio.h>

struct foo {
  void(*xf)(void);
  int r;
} sFoo;

void func(void) {
  sFoo.xf = func; /* <-- like this */
}

int main()
{
  func();
  printf("FuncPtr  is: %p\n", sFoo.xf);
  printf("FuncAddr is: %p\n", &func);
  getchar();
  return 0;
}

我想不出为什么它不应该在便携式上工作,但这并不意味着没有。我已经在 Windows 上使用 MinGW 和 MSVC 以及在 Ubuntu 上使用 gcc 对其进行了测试,并且效果很好。 C 标准几乎保持沉默,只是说 (C99 5.1.1.2) 函数引用在最终翻译阶段得到解决。

我的主要烦恼是我找不到任何确认这是标准行为的东西。过去我遇到过 cmets 说您 无法 从该函数中获取函数的地址,我当时认为这是伪造的,但实际上并没有到现在为止,有时间或倾向去实际检查一下。

【问题讨论】:

  • 注意,带有%p 的打印函数指针是未定义的行为。没有用于打印函数指针的格式说明符。
  • 地址和指针解引用运算符实际上对函数没有任何作用,所以func&amp;func*func 都是一样的(其中func 是一个函数)。使用%p 打印除void * 以外的任何内容都是非标准的。将函数指针转换为 void * 在技术上也是 UB。
  • 它有效。已知函数是函数;因此它的名字是一个指向函数的指针
  • 使用%p,我们可以打印任何指针。无论它指向哪里以及输入哪个

标签: c language-lawyer


【解决方案1】:

你有什么理由不能从函数中获取函数的地址吗?

没有。

C 标准几乎保持沉默,只是说 (C99 5.1.1.2) 函数引用在最终翻译阶段解决。

标准不是沉默的;它只是没有明确解决那个特殊情况。这不是特例。

我的主要烦恼是我找不到任何可以证实这是标准行为的东西。

该标准规定您可以获取函数的地址,并描述了如何获取。它对函数定义中的代码也不例外,因此一般规则适用于那里。实际上,如果您无法在该函数的实现中获得指向该函数的指针,那将是非常不一致的,因为您当然可以从那里调用它(ie递归地)。

我过去遇到过 cmets,它说您无法从该函数中获取函数的地址,我当时认为这是虚假的,但实际上并没有时间或倾向实际检查一下,直到现在。

我倾向于同意这样的 cmets 是错误的,无论它们针对标准 C 的程度如何。不过,也许它们针对的是一些不符合标准的实现。或者你可能记错了。显然,除非您提供参考,并且最好在您的问题中提供上下文引用,否则我无法具体解决任何此类 cmets。

【讨论】:

    【解决方案2】:

    一元 &amp; 运算符的唯一约束如下:

    一元 & 运算符的操作数应该是一个函数指示符、一个 [] 或一元 * 运算符的结果,或者是一个左值 指定一个不是位域且未声明为的对象 寄存器存储类说明符。

    函数标识符满足这一点(也许违反直觉,函数标识符是6.3.2.1p1 中的左值),因此获取它们的地址总是合法的。

    事实上,如果它是非法的,递归函数是不可能的,因为要调用一个函数,你需要使用它的指示符,而6.3.2.1p4将这种使用定义为转换为函数指针:

    函数指示符是具有函数类型的表达式。除了 当它是 sizeof 运算符的操作数时,_Alignof operator,65) 或一元 & 运算符,具有类型的函数指示符 ''函数返回类型'' 被转换为具有 type ''指向函数返回类型的指针''。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-09-07
      • 1970-01-01
      • 1970-01-01
      • 2013-07-25
      • 1970-01-01
      • 2016-12-05
      • 2020-12-03
      • 1970-01-01
      相关资源
      最近更新 更多