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

时间:2012-08-18 22:42:25

标签: c function parameters 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也不等。

任何人都能解释一下吗?

3 个答案:

答案 0 :(得分:12)

引用关于函数声明符的标准草案:

  

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

     

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

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

答案 1 :(得分:1)

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

void foo(void);

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

void foo()
{
}

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

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

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

答案 2 :(得分:0)

C标准将void定义为: -

  

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

和定义

void foo()
{
}

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

函数声明的原型也指定: -

  

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