两个带有void和空参数列表的函数声明

我想知道为什么以下代码:

void foo(void); void foo() { } 

在gcc中有效。 在C中,没有重载和上面的声明(实际上,其中一个是定义)声明两个不同的函数(第一个不接受任何参数,第二个可以接受任何参数)类型)。

但是,如果我们为第一个函数提供定义:

 void foo(void) { } void foo() { } 

由于重新定义,此次编译失败。 但是 ,第一个代码仍然是正确的,可能会令人困惑,如下所示:

 void foo(void); int main(void) { foo(); //OK //foo(5); //Wrong, despite ->the definition<- allows it } void foo() { } 

另一方面,这样的事情是无效的:

 void foo(int); void foo() //error: number of arguments doesn't match prototype { } 

我认为与我的第一个前面的代码相比,编译器的行为有点奇怪。 int不等于(/*empty list*/) ,也不是void

有谁能解释一下?

引用关于函数声明符的标准的晚期草稿:

(6.7.6.3/10)void类型的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。

(6.7.6.3/14)标识符列表仅声明函数参数的标识符。 函数声明符中的空列表是该函数定义的一部分,指定该函数没有参数。

因此,声明和定义的声明符实际上是兼容的,因此引用相同的函数(当然不会发生重载,因为C中不存在这样的事情)

下面的行是一个函数声明,它告诉函数foo的签名:返回值的类型是什么,参数的类型是什么。

 void foo(void); 

下面是一个函数定义,它告诉函数该做什么。 它没有超载任何东西。 定义和声明必须在签名中匹配。 void数据类型允许在函数定义中省略它。

 void foo() { } 

由于void不是可实例化的类型(您不能具有void类型的值),因此可以省略函数定义的签名中的参数。 但是,如果你尝试这样做:

 void foo(void*); void foo() { } 

然后你会有一个编译错误,因为foo应该得到一个指向一个不用担心的类型值的指针。

C标准将void定义为: –

void类型包含一组空值; 它是一种不完整的类型,无法完成。

和定义

 void foo() { } 

意味着参数是空的值集合,对定义有效,因此gcc允许。

函数声明的原型还指定: –

void类型的未命名参数作为列表中唯一项的特殊情况指定该函数没有参数。