这是有问题的构造:
int main (void)
{
int a = 5;
(func)(a);
return 0;
}
Run Code Online (Sandbox Code Playgroud)
使用 GNU GCC C99 编译会发生以下情况:
func被定义为一个函数,那么main()该函数就会被执行。func之前未定义为函数main但是,如果我删除func函数周围的大括号,函数将被隐式声明,因此即使它是在另一个翻译单元中定义的,它也会执行,这是我一直期望的行为。
递归下降解析器通过函数调用表达式的存在来识别函数调用表达式(也根据标准),这(arguments)就是为什么像这样的代码3(a);会发出错误:“被调用的对象不是函数或函数指针”。就像其他类似的操作(例如后缀增量)一样,前面的内容(arguments)预计是一个子表达式 - 在这种情况下,约束需要一个函数或函数指针的操作数。对于所有其他操作,您可以随意添加任意数量的括号:((a))++这不会改变任何事情,但是对于函数调用,它看起来并不完全像那样。
为什么该代码的行为会有所不同,这是我不知道的语言功能,还是一些精心设计的解析设计选择的结果?
这是因为 C89 中如何定义隐式声明。只有裸标识符才有资格作为隐式声明。
C89 标准的第 3.3.2.2 节对此进行了详细说明:
如果函数调用中带括号的参数列表前面的表达式仅包含标识符,并且该标识符没有可见的声明,则隐式声明该标识符,就像在包含函数调用的最内层块中声明
Run Code Online (Sandbox Code Playgroud)extern int identifier();出现了。
因为在这种情况下:
(func)(a);
Run Code Online (Sandbox Code Playgroud)
带括号的参数前面的表达式不仅仅是一个标识符,它不符合隐式声明的条件。
至于为什么即使在 C99 和更高版本的模式下 gcc 似乎仍然允许这样做-pedantic,我将其归因于扩展或错误。