【问题标题】:What do the parentheses around a function name mean?函数名周围的括号是什么意思?
【发布时间】:2012-11-16 01:13:57
【问题描述】:

在我的一个项目源文件中,我找到了这个 C 函数定义:

int (foo) (int *bar)
{
    return foo (bar);
}

注意:foo 旁边没有星号,所以它不是函数指针。或者是吗? 递归调用是怎么回事?

【问题讨论】:

  • 不,它不是函数指针——它仍然是一个名为 foo 的常规函数​​。
  • 这是完整的功能吗?
  • 你有证据表明这个函数被用在了有用的上下文中吗?
  • ...看起来像一些虚拟函数,可能只是为了查看它是否在现有源代码中编译而编写的,应该已被删除。我会删除它(如果这是该函数真正所做的),因为充其量它会是无限循环(我不确定是否允许 C 编译器优化该尾调用以跳转),最坏的情况是堆栈溢出。
  • C 声明中的括号有助于使语言不明确。快,a(b); 是什么?将b 声明为a 类型的变量?或者使用参数b 调用函数a?区别在于语法,如果不查找a 的声明信息,您甚至无法知道如何解析它;即那些后缀函数调用括号,或声明符周围的可选括号。

标签: c function parentheses


【解决方案1】:

在没有任何预处理器的情况下,foo 的签名相当于

int foo (int *bar)

我看到人们在函数名称周围加上看似不必要的括号的唯一情况是,当同时存在同名的函数和类似函数的宏,并且程序员想要防止宏扩展时。

这种做法一开始可能看起来有点奇怪,但 C 库开创了 providing some macros and functions with identical names 的先例。

这样的一个函数/宏对是isdigit()。该库可能将其定义如下:

/* the macro */
#define isdigit(c) ...

/* the function */
int (isdigit)(int c) /* avoid the macro through the use of parentheses */
{
  return isdigit(c); /* use the macro */
}

您的函数看起来与上面的几乎相同,所以我怀疑这也是您的代码中发生的事情。

【讨论】:

  • 这里可能也是这样;我没有寻找宏...而且我不知道宏扩展不会发生在括号内,感谢您指出!
  • @user1859094:再看一遍,几乎可以肯定这就是您的代码中发生的事情。函数内部的foo(bar)使用的是对应的宏。
  • @user1859094 宏扩展确实发生在括号内,但类似函数的宏的扩展只有在下一个标记是左括号时才会发生(C99,6.10.3§10),因此@987654327 @ 会被替换,但不会被替换为 (foo) (int *bar)foo 之后的下一个标记是 )
  • 这样的函数怎么调用?你也会用括号来称呼它吗?例如,这是否可行:(isdigit)(5)?
  • @Greg:没错,你就是这么称呼它的。
【解决方案2】:

括号并没有改变声明 - 它仍然只是定义一个名为foo的普通函数。

之所以使用它们,几乎可以肯定是因为定义了一个名为foo的类似函数的宏:

#define foo(x) ...

在函数声明中使用(foo) 可防止此宏在此处展开​​。因此,可能发生的情况是,正在定义一个函数 foo(),其主体从类似函数的宏 foo 扩展而来。

【讨论】:

  • 很好的推论(尽管为此使用括号应该受到法律的惩罚)。
  • @ugoren:在函数名周围使用括号是防止类函数宏的宏扩展的唯一方法。有时它是必要的工具。
  • @MichaelBurr,也可以选择不使用同名的宏和函数。我知道你不能总是控制一切,但如果你达到了这个解决方案,我会说有些地方很不对劲。
【解决方案3】:

括号没有意义。
您显示的代码不过是无限递归。

在定义函数指针时,您有时会看到奇怪的括号,它们确实意味着什么。但这里不是这样。

【讨论】:

  • 显然不是;括号防止宏扩展。查看接受的答案。
  • @Kevin,我的回答是关于显示的代码,并且是正确的。在这里几乎所有的 C 问题中,假设未知的预处理器定义可以改变一切。在这种情况下,考虑预处理器的答案确实更好,但不会使我的答案不正确。
猜你喜欢
  • 2011-04-02
  • 1970-01-01
  • 2014-10-01
  • 2010-10-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多