【问题标题】:C function pointersC 函数指针
【发布时间】:2011-08-15 15:01:00
【问题描述】:
static void increment(long long *n){
  (*n)++;
}

struct test{
  void (*work_fn)(long long *);
};

struct test t1;

t1.work_fn = increment;

我现在如何实际调用该函数? t1.work_fn(&n) ?

【问题讨论】:

  • 是的,函数指针的作用类似于常规函数。一个势利的答案是:你为什么不试试看呢? :)
  • 你试过了吗?结果是什么?真的,编写代码、运行它、测试它、在调试器中观察它都没有错。
  • @abelenky:有,如果你不确定你是依赖未定义的行为,还是非标准的语言扩展等。

标签: c++ c pointers


【解决方案1】:

我现在如何实际调用该函数? t1.work_fn(&n)?

这样就可以了。

函数指针不需要显式取消引用。这是因为即使在正常调用函数时(使用函数的实际名称),您实际上也是通过指向函数的指针调用它。 C99 6.5.22“函数调用”说(强调我的):

表示被调用函数的表达式(脚注 77)应具有指向函数的类型指针返回 void 或返回数组类型以外的对象类型

脚注 77:

大多数情况下,这是转换作为功能指示符的标识符的结果。

请注意,由于 C99 6.5.3.2/4 “地址和间接运算符”说:

一元 * 运算符表示间接。如果操作数指向一个函数,则结果是一个函数指示符

所以所有这些最终都会做同样的事情(尽管编译器可能也无法优化通过 t1.work_fn 的调用):

t1.work_fn(&n);
(*t1.work_fn)(&n);

increment(&n);
(*increment)(&n);

【讨论】:

  • 事实上,在值上下文中的源代码级别,可以根据需要多次取消引用函数[指针]。函数foo 可以被称为foo()(*foo)()(*******foo)(),在所有这些情况下具有相同的行为。
  • @Andrey:我正要添加评论。
【解决方案2】:

您可以将其称为t1.work_fn(&n)(*t1.work_fn)(&n),无论您喜欢哪个。

对称地,在分配指针时,您可以使用t1.work_fn = incrementt1.work_fn = &increment。同样,这是个人编码风格的问题。

人们可能会争辩说,为了保持一致性,应该坚持“简约”风格

t1.work_fn = increment;
t1.work_fn(&n);

或“极简主义”风格

t1.work_fn = &increment;
(*t1.work_fn)(&n);

但不是两者的混合,这样我们就可以在两个不同的阵营而不是四个阵营之间进行明确的圣战。

附:当然,“简约”风格是唯一合适的风格。并且必须在尖端敲碎鸡蛋。

【讨论】:

    【解决方案3】:

    是的,就是这样称呼它的。函数名和包含函数指针的变量本质上是一回事。

    【讨论】:

    • 嗯...我的记忆说不同。但由于任务有效,这是有道理的。这在 1990 年就已经这样运作了吗?还是随着 C 的最新版本之一而改变?
    • @Aaron:我注意到了。我要去寻找一个真正的参考,所以不仅仅是我记得/你记得。
    • 在价值环境中(比如打电话时),它们确实充当“同一件事”。当然,在对象上下文中它们是不一样的。例如,将一元 & 应用于函数和指针将产生完全不同的结果。这种情况类似于数组:它们的行为通常像指针,但通常它们不是。
    • @AndreyT:感谢您澄清这一点。我刚刚找到 C99 §6.5.2.2。
    • @Aaron - 它在 1990 年就是这样工作的。至少从 K&R 1 (1978) 开始就是这样。