我目前正在重构/整理一些旧的 C 代码,该代码用于一个 C++ 项目中,经常会看到以下类型的函数:
int f(void)
我倾向于这样写:
int f()
替换代码库中的所有(void)为()以提高一致性是否有任何原因不这样做,或者我没有意识到两者之间的微妙差异?
更具体地说,如果C++中的虚成员函数被描述为:
virtual int f(void)
派生类包括一个成员函数:
int f()
这是一个有效的重载吗?此外,基于几乎相同的签名,我是否可能遇到任何链接器问题?
我目前正在重构/整理一些旧的 C 代码,该代码用于一个 C++ 项目中,经常会看到以下类型的函数:
int f(void)
我倾向于这样写:
int f()
替换代码库中的所有(void)为()以提高一致性是否有任何原因不这样做,或者我没有意识到两者之间的微妙差异?
更具体地说,如果C++中的虚成员函数被描述为:
virtual int f(void)
派生类包括一个成员函数:
int f()
这是一个有效的重载吗?此外,基于几乎相同的签名,我是否可能遇到任何链接器问题?
int f(void)
表示返回整数的函数不接受参数。而声明 int f()
则表示返回整数的函数可以接受任意数量的参数。因此,如果你在C语言中有一个不接受参数的函数,那么前者是正确的原型。int f(void)
已经被弃用了,int f()
更受欢迎,因为它明确表示一个不接受参数的函数。f(void)
而不是f()
。这确实是因为答案所述的原因。 - Martin Scharrerint f()
是不好的实践方法,因为你会失去编译器将函数声明与其定义进行比较以确保正确调用的能力。#include <stdio.h>
void foo();
void bar(void) {
foo();
}
void foo(int a) {
printf("%d\n", a);
}
但这会导致未定义的行为,因为 a
没有被传递给 foo
。
C++中有两个版本的 foo
:一个不带参数,另一个带一个 int
。因此,bar
最终调用了未定义的版本,这将导致链接错误(假设没有其他任何地方定义了 foo
)。
值得注意的是,func(void)语法在C++中并没有被弃用,但通常被认为更像是C风格的习惯用法。我认为我遇到的大多数C++程序员更喜欢使用空参数列表。C语言区分具有空参数列表声明的函数和仅包含void参数列表声明的函数。前者是未经原型处理的函数,接受未指定数量的参数,而后者是使用原型处理的不接受任何参数的函数。
C++则不区分这两种声明,都表示不接受任何参数的函数。
对于旨在编译为C或C++的代码,解决此问题的最佳方法是始终使用显式void原型声明不带参数的函数。
C99中空函数原型是一种已弃用的特性(就像C89一样)。
void f()
已被弃用,建议使用 void f(void)
:
6.11.6 函数声明符:
1 使用空括号(不是原型格式参数类型声明符)的函数声明符是一个废弃特性。
前言:
2 某些特性是废弃的,这意味着它们在此国际标准的未来修订中可能被考虑撤回。它们被保留,是因为它们被广泛使用,但对于新实现(对于实现功能)或新程序(对于语言 [6.11] 或库特性 [7.31]),不鼓励使用它们。
详细讨论:https://dev59.com/8HRB5IYBdhLWcg3wLkxM#36292431
既不推荐使用 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)
,这可能并不值得。
简而言之:请使用void
。
考虑到C++的向后兼容性以及下面所识别的一点模棱两可,我认为我们应该回到K&R和ANSI C,寻找一个确定的答案:
int getline(void);
int copy(void)
getline()
和copy()
。但是为了与旧的C程序兼容,标准采用空列表作为旧式声明,并关闭所有参数列表检查;必须使用单词void
表示显式的空列表。[Kernighan & Richie,the C programming language,1988,Pgs 32-33]int f(void)
是一个已弃用的声明,与int f()
完全等效。它们的签名是相同的,void
在这种情况下与空格一样重要。这也意味着它们受到“单一定义规则”的约束(它们不会重载),Derived::f(void)
覆盖了Base::f()
。f(const void)
这样的东西,因为对于这种奇怪的声明并没有太多共识。