我想知道为什么以下代码:
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
也不等。
任何人都能解释一下吗?
答案 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类型的未命名参数的特殊情况作为唯一项目 在列表中指定该函数没有参数。