多个相同原型合法吗?

问题描述 投票:0回答:1

以下代码在

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 prototype language-lawyer declaration c99
1个回答
5
投票

多个相同的原型是合法的,而且实际上很常见,因为在现代 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)
兼容,因为它们指定了不同数量的参数。

© www.soinside.com 2019 - 2024. All rights reserved.