【问题标题】:About a declaration of function pointer关于函数指针的声明
【发布时间】:2018-11-20 13:28:37
【问题描述】:

我正在考虑以下之间的区别:

void *signal(int, void (*)(int))(int)

void (*signal(int, void (*)(int)))(int)

我知道后者来自here - Example #3: The ``Ultimate''(当我尝试大声说出来理解它时,这是一次有趣的学习经历):

signal 是一个以(int, void (*)(int)) 为输入的函数,并返回指向另一个以(int) 为参数并返回void 的函数的指针。

对于前者,我认为自从最后一个 (int) 将具有比 * 更高的优先级,所以它应该是一个语法错误,但从 cdecl.org 开始,结果是:

["] 将信号声明为函数 (int, 指向函数的指针 (int) 返回 void) 返回函数 (int) 返回指向 void 的指针 [."]

所以我需要一张支票。

【问题讨论】:

  • 问题是什么?
  • @Lundin: 是的,我的问题是我使用像 precedence order 这样的技术来理解这种定义,在前一个我认为最后一个 (int) 会在第一个* 之前先关联,这将导致语法错误。如果您想知道,您会看到我对@Michael Kenzel 的回答的评论。
  • 这与运算符优先级完全无关。如果您想在阅读晦涩的内容时获得一些帮助,请查看:c-faq.com/decl/spiral.anderson.html
  • @Lundin:你说得对,但这是我在问题中提供的链接,我阅读了这些描述,但我从聊天室中的某个人那里得到了链接,他说这不是一种正式的技术。跨度>
  • @Lundin:好的,抱歉我的错误,我从int *a[2][2] 之类的示例中得出结论,首先是右关联,然后将剩余的int * 作为数组中的元素类型处理。然后我认为这也适用于给定标识符之后的括号()

标签: c function-pointers


【解决方案1】:

必须区分语法和语义。 cdecl.org 只为您提供输入的任何声明符的语法含义。在您的第一个示例中,您确实将signal语法正确声明为返回函数的函数。但是,C 不允许函数返回其他函数:

N1570 6.7.6.3 §1:

函数声明器不得指定函数类型或数组类型的返回类型。

因此,虽然此声明在语法上正确,但在语义上无效。换句话说:虽然 C 语法可以编写“函数返回函数”,但实际上不允许在程序中拥有返回函数的函数。就像英语(或任何语言)也可以让你表达各种物理上不可能实现的想法......

【讨论】:

  • 在前一种情况下,signal 之前的* 是否仍会在最后一个(int) 之前关联?我正在考虑我是否使用这种 优先顺序 会不会在其他情况下造成任何麻烦。
  • 是的,根据所涉及的运算符的优先级来考虑声明是正确的方法。至少按照我的理解。 () 总是比* 绑定得更牢固。因此,如果您有void *signal()(),那么您将其解读为“信号是一个返回指向void 的指针的函数的函数”。如果你有void *signal()()() 那么那将是一个返回函数的函数……
【解决方案2】:

这里最重要的部分是......你不需要学习这个,它是语言中设计得很糟糕的部分。您可以向下滚动到答案的底部以找到理智、专业的解决方案。

否则,如果你坚持,它会这样......


当试图从函数返回函数指针时,函数指针的类型会被拆分。如果你想返回一个函数指针void(*)(void),那么这个糟糕的函数指针会被分成三部分。让我们这样称呼他们:

  • void 是 A,指向函数的返回类型。
  • (*) 是 B,将其标记为指向函数的指针,而不是函数。
  • (void)是C,指向函数的参数。

然后,如果我们想把它作为返回类型粘贴到其他一些 icky 函数声明中,它们最终会是这样的:

#define A void
#define B *
#define C (void)

// A (B) C equals void(*)(void)

A (B madness(int, void (*fp)(int))) C;

其中 A、B 和 C 是我们要返回的可怜的函数指针的部分,madness 是函数的名称,其余部分是函数本身用作参数的一些混乱。

如果我们省略 B 部分,它将被解释为返回另一个类型为 void f (void); 的无效函数。语法允许,但语言规范不允许。

同样,int foo (void) [3]; - 也不允许返回数组的函数。


思考这些事情是发疯的道路,它使代码不可读。专业程序员使用typedef

给定

void (*madness(int, void (*f)(int)))(int);

替换为:

typedef void func_t (int);

func_t* sanity (int, func_t* f);

【讨论】:

  • 当你回答时,我确实找到了你最后提到的something,是的,这就是我之前放弃 C/C++ 的原因。
猜你喜欢
  • 1970-01-01
  • 2012-03-08
  • 1970-01-01
  • 1970-01-01
  • 2018-11-11
  • 2020-04-13
  • 2013-03-16
  • 1970-01-01
相关资源
最近更新 更多