Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/azure/11.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C 多个相同的原型合法吗?_C_Prototype_Language Lawyer_Declaration_C99 - Fatal编程技术网

C 多个相同的原型合法吗?

C 多个相同的原型合法吗?,c,prototype,language-lawyer,declaration,c99,C,Prototype,Language Lawyer,Declaration,C99,以下代码在Linux x64上使用gcc和clang编译时不会发出任何警告: #include <stdio.h> #include <stdlib.h> void foo(void); void foo(void); void foo(void); int main(void) { return 0; } #包括 #包括 void foo(void); void foo(void); void foo(void); 内部主(空) { 返回0; } 依

以下代码在
Linux x64
上使用
gcc
clang
编译时不会发出任何警告:

#include <stdio.h>
#include <stdlib.h>

void foo(void);

void foo(void);

void foo(void);

int main(void)
{
    return 0;
}
#包括
#包括
void foo(void);
void foo(void);
void foo(void);
内部主(空)
{
返回0;
}
依我看,根据C99的以下片段,这是合法的:

引用同一对象或函数的所有声明应具有 兼容型;否则,行为是未定义的

(……)

双功能 要兼容的类型,两者都应指定兼容的返回类型

(……)

此外,参数类型列表(如果两者都存在)应在 参数数量和省略号终止符的使用情况;相应的 参数应具有兼容类型

(……)

如果两种类型的类型相同,则它们具有兼容的类型


我说得对吗?我想确保它不是UB,并且我的理解是正确的。

多个相同的原型是合法的,事实上是常见的,因为在现代C语言中,函数定义通常包含该函数的原型,并且在包含头文件的范围内也包含该函数的原型。也就是说

foo.h

void foo(int x);
#include "foo.h"

void foo(int x) {
    printf("%d\n", x);
}

/* ... */
extern int global;
#include "global.h"

int global = 42;
foo.c

void foo(int x);
#include "foo.h"

void foo(int x) {
    printf("%d\n", x);
}

/* ... */
extern int global;
#include "global.h"

int global = 42;
在函数体
foo
的定义和整个文件的其余部分中,有两个相同的
foo()
原型。这很好

同一对象或函数的多个声明不完全相同也是可以的,只要它们是兼容的。例如 声明

void foo();
foo
声明为接受未指定参数但不返回任何内容的函数。此声明与
foo.c
foo.h
中已经存在的声明兼容,并且可以将其添加到这些文件中的一个或两个,而不会产生任何附加效果

这也适用于对象(变量),其中一些应用程序非常常见。例如,如果要声明从多个文件访问的全局变量,则通常在头文件中声明该变量。包含该变量的C源文件和该变量的定义(也是一个声明)通常包含头,产生两个声明:

global.h

void foo(int x);
#include "foo.h"

void foo(int x) {
    printf("%d\n", x);
}

/* ... */
extern int global;
#include "global.h"

int global = 42;
global.c

void foo(int x);
#include "foo.h"

void foo(int x) {
    printf("%d\n", x);
}

/* ... */
extern int global;
#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
的多个兼容但不完全相同的声明。如果不对其中一种类型进行多次声明,则无法声明这组特定的数据结构。

C标准为C11。不要使用标准的无效过时版本进行讨论。如果您真的使用c99
如果您真的使用c99
,您可以将其标记为c99而不是c-我听说大多数编译器仍然没有实现所有的
c99
功能,更不用说
C11
,所以我想知道“真的使用c99”是什么意思只要声明是等价的,就可以重复声明。例如,给定
typedef int int32_2,都是
int函数(int,int)
int32_t函数(int,int32_t)是等效的。@Weather Vane,这在编译单元中是如何实现的?链接时会分配多个冲突的存储位置?关于定义中的重复原型,这一点很好-我甚至没有想到这一点!还有一件事-如果您有时间,您能否确认我对
C99
C11
标准中哪些部分描述了该行为是正确的,或者我应该在标准的另一部分中寻找解释?最近我开始喜欢阅读官方标准,一开始它们似乎很难理解,你读得越多你就理解得越多。我认为作为函数定义的
void foo(){…}
void foo(void){…}
相同,而声明
void foo()
void foo()不同(void)
(C99)。你的想法或这是否超出了本文的范围?@chux,在C99和c211中,
foo()
是一个带有空[参数]标识符列表的函数声明器,而
foo(void)
是一个带有单元素参数类型列表的函数声明器(其中一个元素是匿名的)。当这些参数作为函数定义的一部分出现时,它们对于函数的参数具有相同的含义,但只有包含参数类型列表的声明符可用作原型(C99 6.9.1/7;C2011 6.9.1/7;以及其他地方),无论是否在函数定义中。当然,在函数定义之外,它们有不同的含义。@chux,这也意味着采用参数的函数的K&R风格的定义不能作为该函数的原型。实际上,我在这方面的回答措辞相当谨慎,以便准确,而不必深入研究t他提出了这个问题。