6

我想知道为什么下面的代码:

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

谁能解释一下?

4

3 回答 3

12

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

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

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

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

于 2012-08-18T22:57:38.613 回答
1

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

void foo(void);

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

void foo()
{
}

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

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

那么您将遇到编译错误,因为foo预计会获得指向 don't-worry-about-type 值的指针。

于 2012-08-18T22:47:30.877 回答
0

C标准将void定义为:-

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

和定义

void foo()
{
}

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

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

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

于 2012-08-18T22:50:17.630 回答