【问题标题】:Two function declarations with void and empty argument list两个带有 void 和空参数列表的函数声明
【发布时间】:2012-08-18 22:42:24
【问题描述】:

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

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 也不等于。

谁能解释一下?

【问题讨论】:

标签: c function parameters void


【解决方案1】:

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

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

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

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

【讨论】:

  • 答案是:作为该函数定义一部分的函数声明器中的空列表指定该函数没有参数。。如果反过来,声明为void foo(); 和定义void foo(void) {},这将不成立。您的答案是唯一真正注意到这种差异的答案。 +1
  • 第 14 个项目符号实际上继续说明空列表对于声明符不属于定义的一部分意味着什么,对于那些应该关心的人来说。
  • @eq- 好吧,如果函数定义中的空列表指定函数不接受任何参数,那么为什么 gcc 允许这样的事情:void f() {} //call: f(6, 7, 3.14) &lt;- OK?我们必须通过将void 放在其参数列表中来明确指出该函数没有参数,以使 gcc 发出错误...
  • @Quentin,不能确定。也许编译器中存在错误,或者可能是更早的标准(比 C11)有不同的措辞,而 GCC 符合这一点(或者也许是我得出错误的结论,谁知道)
  • @Quentin,这似乎不是是这样的。我对标准的解释是,两者在函数内是相同的,但只有前者引入了函数原型。这与您之前描述的 GCC 行为兼容。但是,这些定义是兼容的(正如我在答案中所述)。
【解决方案2】:

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

void foo(void);

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

void foo()
{
}

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

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

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

【讨论】:

  • 问题是为什么它可以工作,因为签名看起来不一样。
  • 签名匹配,因为void 不是可实例化的数据类型。 void 什么都没有。但是,如果你把void *放在函数声明中,如果你不把它也放在函数定义中,就会引发编译错误。
【解决方案3】:

C 标准将 void 定义为:-

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

以及定义

void foo()
{
}

表示参数是对定义有效的空值集,因此 gcc 允许。

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

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

【讨论】:

    猜你喜欢
    • 2011-07-09
    • 2016-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-10-01
    • 2012-12-02
    • 2012-02-14
    相关资源
    最近更新 更多