现代的C和C++中,f(void)是否已经被弃用?

68

我目前正在重构/整理一些旧的 C 代码,该代码用于一个 C++ 项目中,经常会看到以下类型的函数:

int f(void)

我倾向于这样写:

int f()

替换代码库中的所有(void)为()以提高一致性是否有任何原因不这样做,或者我没有意识到两者之间的微妙差异?

更具体地说,如果C++中的虚成员函数被描述为:

virtual int f(void)

派生类包括一个成员函数:

int f()

这是一个有效的重载吗?此外,基于几乎相同的签名,我是否可能遇到任何链接器问题?


11
请注意不要像这样将C和C++过于简单地混为一谈。需要考虑到它们之间的差异。 - Brian Knoblauch
1
复制:https://dev59.com/eGs05IYBdhLWcg3wJuvp - Will Bickford
4
@Will,这是两年后问的重复问题 ;) 翻译:这是两年后重复提出的类似问题,针对Will用户。 - SmacL
3
@Shane: 我能看穿时间!另一个答案提供了更多细节。 :) (译文:@Shane说:"I can see through time! ",另一个回答提供了更详细的信息。 :)) - Will Bickford
1
@Ciro,类似的问题但并不完全相同。我想问的是某个版本是否被弃用并且需要重构,如果是的话,在与其他代码(包括静态链接库)一起工作时是否容易导致可能的签名冲突问题。 - SmacL
显示剩余2条评论
6个回答

101
在C语言中,声明 int f(void) 表示返回整数的函数不接受参数。而声明 int f() 则表示返回整数的函数可以接受任意数量的参数。因此,如果你在C语言中有一个不接受参数的函数,那么前者是正确的原型。
在C++中,我认为 int f(void) 已经被弃用了,int f() 更受欢迎,因为它明确表示一个不接受参数的函数。

24
我不知道在C语言中void f()意味着任意数量的参数,感谢你指出来。 - Dominik Grabiec
14
我不会用“接受任意数量的参数”这个措辞,因为它意味着“接受未知类型和数量的参数”。如果传入错误数量的参数,将导致未定义行为。而“...”表示函数接受任意数量的额外参数。 - Johannes Schaub - litb
1
据我所知,该语法并未被弃用(Stroustrup本人曾说过,“K&R书中的每个程序也都是一个有效的C++程序”,但正如其他人指出的那样,它被认为是一种C-ism。我更喜欢使用它来明确地表示函数不需要参数。如果你需要与C共享代码,这也会有所帮助。 - Joe Pineda
4
你说得对,乔,这不是C ++中的弃用语法。我之前已经检查过标准了。但有趣的是,空参数列表自1989年起就成为C语言中的弃用语法! - Dan Olson
当编写用于安全应用程序(汽车、航空等)的C代码时,必须遵循严格的编码指南(例如汽车MISRA),其中之一是需要编写f(void)而不是f()。这确实是因为答案所述的原因。 - Martin Scharrer

21
为补充 Chris 的回答,在我的经验中,在 C 中使用 int f() 是不好的实践方法,因为你会失去编译器将函数声明与其定义进行比较以确保正确调用的能力。
例如,以下代码符合标准的C:
#include <stdio.h>

void foo();

void bar(void) {
    foo();
}

void foo(int a) {
    printf("%d\n", a);
}

但这会导致未定义的行为,因为 a 没有被传递给 foo

C++中有两个版本的 foo:一个不带参数,另一个带一个 int。因此,bar 最终调用了未定义的版本,这将导致链接错误(假设没有其他任何地方定义了 foo)。


好的观点,谢谢。但我认为你应该补充说明这是C语言中的不良实践,而不是C++。 - Chris Young
2
我并不认为你需要使用“根据我的经验”这样的限定词,因为这几乎是毫无保留地不好的做法。唯一能接受的情况是当C编译器是一个不支持函数原型的C89前编译器时;然而这种情况在如今十分罕见。 - Jonathan Leffler

18
之前的答案是相当正确的,但我会链接到David Tribble的优秀页面,因为它提供了关于这个问题和许多其他问题的很好的解释
重点内容如下:

C语言区分具有空参数列表声明的函数和仅包含void参数列表声明的函数。前者是未经原型处理的函数,接受未指定数量的参数,而后者是使用原型处理的不接受任何参数的函数。

C++则不区分这两种声明,都表示不接受任何参数的函数。

对于旨在编译为C或C++的代码,解决此问题的最佳方法是始终使用显式void原型声明不带参数的函数。

C99中空函数原型是一种已弃用的特性(就像C89一样)。

值得注意的是,func(void)语法在C++中并没有被弃用,但通常被认为更像是C风格的习惯用法。我认为我遇到的大多数C++程序员更喜欢使用空参数列表。
引用C++标准第8.3.5节第2段的一句话:
“如果parameter-declaration-clause为空,则该函数不带参数。参数列表(void)等效于空参数列表。除了这种特殊情况外,void不应是参数类型(虽然从void派生的类型,如void*,可以)。”
没有提到任何一种形式被弃用。再次感谢Tribble先生的优秀网站,为我指出了正确的标准部分。

2

C11 N1570 标准草案

void f() 已被弃用,建议使用 void f(void)

6.11.6 函数声明符

1 使用空括号(不是原型格式参数类型声明符)的函数声明符是一个废弃特性。

前言

2 某些特性是废弃的,这意味着它们在此国际标准的未来修订中可能被考虑撤回。它们被保留,是因为它们被广泛使用,但对于新实现(对于实现功能)或新程序(对于语言 [6.11] 或库特性 [7.31]),不鼓励使用它们。

详细讨论:https://dev59.com/8HRB5IYBdhLWcg3wLkxM#36292431

C++11 N3337 标准草案

既不推荐使用 void f(),也不弃用。为了与 C 兼容,void f(void) 存在。 附录 C "兼容性" C.1.7 第 8 条:声明符

8.3.5 变更:在 C++ 中,使用空参数列表声明的函数不带参数。在 C 中,空参数列表表示函数参数的数量和类型是未知的。

由于在 C 中已经弃用了 void f(),并建议使用 void f(void),所以只要 C++ 想保持兼容性,void f(void) 就会存在。

void f(void)void f() 在 C++ 中是相同的。因此,只有当您关心编写可以在 C 和 C++ 下编译的代码时,才有意义使用较长的 void f(void),这可能并不值得。

详细讨论:https://dev59.com/FnVD5IYBdhLWcg3wNY1Z#36835303


2

简而言之:请使用void

考虑到C++的向后兼容性以及下面所识别的一点模棱两可,我认为我们应该回到K&R和ANSI C,寻找一个确定的答案:

int getline(void);
int copy(void)

由于专用版本的getline和copy没有参数,因此逻辑上应该在文件开头声明它们的原型为getline()copy()。但是为了与旧的C程序兼容,标准采用空列表作为旧式声明,并关闭所有参数列表检查;必须使用单词void表示显式的空列表。[Kernighan & Richie,the C programming language,1988,Pgs 32-33]
对于新程序,使用空参数列表具有意图让旧的C程序能够与新编译器一起编译。但是使用新程序时这样做是不好的做法。如果函数需要参数,请声明它们;如果不需要参数,请使用void。[ibid, Pg. 73]
我将余下内容分成了一个单独的讨论:指定在没有参数的函数声明中使用void是否解决了最棘手的语法问题?

-1
在C++中,int f(void)是一个已弃用的声明,与int f()完全等效。它们的签名是相同的,void在这种情况下与空格一样重要。这也意味着它们受到“单一定义规则”的约束(它们不会重载),Derived::f(void)覆盖了Base::f()
不要去碰像f(const void)这样的东西,因为对于这种奇怪的声明并没有太多共识。

1
上面的答案说f(void)没有被弃用。能否有人提供一下标准中关于f(void)是否被弃用的链接或引用? - Chris Lutz
我已经编辑了我的答案,包括引用和引文。 - Dan Olson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接