以下代码在
gcc
上同时使用 clang
和 Linux x64
编译时不会发出任何警告:
#include <stdio.h>
#include <stdlib.h>
void foo(void);
void foo(void);
void foo(void);
int main(void)
{
return 0;
}
IMO,根据 C99 的以下片段,这是合法的:
引用同一对象或函数的所有声明都应具有 兼容类型;否则,行为是未定义的。
(...)
对于两个功能 类型要兼容,两者都应指定兼容的返回类型
(...)
此外,参数类型列表(如果两者都存在)应在 参数的数量以及省略号终止符的使用;相应的 参数应具有兼容的类型。
(...)
如果两种类型的类型相同,则它们具有兼容类型。
我说得对吗?我想确定它不是 UB 并且我的理解是正确的。
多个相同的原型是合法的,而且实际上很常见,因为在现代 C 中,函数定义包含该函数的原型,并且在包含头文件的范围内也有该函数的原型。 也就是说,给定
foo.h:
void foo(int x);
foo.c:
#include "foo.h"
void foo(int x) {
printf("%d\n", x);
}
/* ... */
在函数
foo()
的定义主体以及整个文件的其余部分中,foo
的作用域中有两个相同的原型。 这很好。
同一个对象或函数的多个声明不相同也是可以的,只要它们兼容即可。 例如, 声明
void foo();
将
foo
声明为接受未指定参数且不返回任何内容的函数。 此声明与 foo.c
和 foo.h
中已有的声明兼容,并且可以将其添加到这些文件中的一个或两个文件中,附加效果为零。
这也适用于对象(变量),其中一些应用程序非常常见。 例如,如果您想声明一个可从多个文件访问的全局变量,那么通常将该变量的声明放在头文件中。 包含该变量的 C 源文件及其定义(这也是一个声明),通常
#include
是标头,产生两个声明:
global.h:
extern int global;
global.c:
#include "global.h"
int global = 42;
或者存在复合数据类型前向声明的情况:
struct one;
struct two {
struct one *my_one;
struct two *next;
};
struct one {
struct two *my_two;
}
请注意
struct one
的多个兼容但不相同的声明。 如果不多次声明其中一种类型,则根本无法声明这一特定的数据结构集。
附录回复:C2X
C2X 在该领域引入了相关更改:从该版本的 C 开始,不包含参数类型列表的函数声明声明该函数采用零参数,如 C++ 中一样,而在以前的 C 版本中,此类声明不提供任何参数类型列表。有关参数数量或类型的信息。 因此,在 C2X 及更高版本中,函数声明
void foo()
不再与 void foo(int)
兼容,因为它们指定了不同数量的参数。