函数名称周围的括号是什么意思?


214

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

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

注意:旁边没有星号foo,因此它不是函数指针。还是?递归调用在这里发生了什么?


7
不,它不是函数指针-仍然是名为foo的常规函数​​。
Nemanja Boric 2012年

这是完整功能吗?
asheeshr 2012年

2
您是否有证据证明此功能在有用的上下文中使用?
moooeeeep 2012年

1
...看起来像一些伪函数,可能只是为了查看它是否已在现有源代码中编译而编写的,应该已被删除。我会删除它(如果那是函数真正的作用),因为充其量是死循环(我不确定是否允许C编译器优化该尾调用来跳转),这是最糟糕的堆栈溢出。
海德

3
C声明中的括号有助于消除该语言的歧义。快速,什么是a(b);?声明b为类型变量a?还是a带有参数的函数调用b?区别是语法上的,如果不查找a; 的声明信息,就无法知道解析该方法的方式。即是那些postfix函数调用括号,还是声明符周围的可选括号。
卡兹(Kaz)2012年

Answers:


329

在没有任何预处理程序发生的情况下,foo的签名等效于

int foo (int *bar)

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

起初这种做法似乎有些奇怪,但是C库通过提供一些具有相同名称的宏和函数来树立了先例。

一个这样的功能/宏对是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 */
}

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


2
这里也可能是这种情况。我没有寻找宏...而且我不知道宏扩展不会在括号内进行,谢谢指出!
user1859094

13
@ user1859094:从第二个角度看,这几乎可以肯定是代码中正在发生的事情。的foo(bar)在函数内部中使用相应的宏。
NPE 2012年

78
@ user1859094宏的确在括号内进行扩展,但仅在下一个标记为左括号(C99,6.10.3§10)的情况下,才进行类函数宏的扩展,因此foo (int* bar)将被替换,但不会被替换(foo) (int *bar)(下一个标记)之后foo)
Virgile

4
这样的函数将如何被调用?您也可以用括号来称呼它吗?例如,这可以工作(isdigit)(5)吗?
gcochard

4
@Greg:是的,这就是您的称呼。
NPE 2012年

37

寄生函数不会改变声明,它仍然只是定义一个称为的普通函数foo

使用它们的原因几乎可以肯定是因为有一个类似于函数的宏,称为foodefine:

#define foo(x) ...

使用(foo)函数声明防止这里被扩展这个宏。因此,可能发生的情况是foo()定义了一个函数,并从类似函数的宏中扩展了其主体foo


5
很好的推论(尽管为此目的使用括号应受到法律的惩罚)。
ugoren

3
@ugoren:在函数名称周围使用括号是防止类似函数的宏扩展的唯一方法。有时它是必要的工具。
Michael Burr 2012年

7
@MichaelBurr,也可以选择不具有相同名称的宏和函数。我知道您无法始终控制所有内容,但是如果您达到此解决方案,我会说有些错误。
ugoren 2012年

-3

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

在定义函数指针时,有时您会看到确实包含某些含义的奇怪括号。但是这里不是这种情况。


6
显然不是;括号可防止宏扩展。请参阅已接受的答案。
凯文(Kevin)

12
@Kevin,我的回答与所显示的代码有关,并且是正确的。在这里几乎所有的C问题中,假设未知的预处理程序定义都可以改变一切。在这种情况下,考虑到预处理器的答案确实更好,但是这不会使我的答案不正确。
ugoren
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.