哪个更好:void foo()或void foo(void)? 使用void时,它看起来很丑且不一致,但有人告诉我它很好。这是真的吗?
编辑:我知道一些旧的编译器做奇怪的事情,但如果我只是使用GCC,是void foo()好吗?将foo (bar);然后被接受?
哪个更好:void foo()或void foo(void)? 使用void时,它看起来很丑且不一致,但有人告诉我它很好。这是真的吗?
编辑:我知道一些旧的编译器做奇怪的事情,但如果我只是使用GCC,是void foo()好吗?将foo (bar);然后被接受?
当前回答
除了语法上的差异,许多人还出于实际原因更喜欢使用void函数:
如果你正在使用搜索函数并想要找到函数的实现,你可以搜索function(void),它将返回原型以及实现。
如果省略void,则必须搜索function(),因此也将找到所有函数调用,从而使查找实际实现更加困难。
其他回答
Void foo(Void)更好,因为它显式地说:不允许有参数。
Void foo()意味着你可以(在某些编译器下)发送参数,至少如果这是你的函数的声明而不是它的定义。
void foo(void);
这是在C中说“无参数”的正确方式,在c++中也适用。
But:
void foo();
在C和c++中意味着不同的东西!在C语言中,它的意思是“可以接受任何数量的未知类型的参数”,在c++中,它的意思与foo(void)相同。
变量参数列表函数本质上是非类型安全的,应该尽可能避免使用。
在c++中,main()和main(void)没有区别。
但在C语言中,main()将被调用时带有任意数量的参数。
例子:
main (){
main(10, "abc", 12.28);
// Works fine!
// It won't give the error. The code will compile successfully.
// (May cause a segmentation fault when run)
}
Main (void)将不带任何参数被调用。如果我们试图传递它,那么这最终会导致编译器错误。
例子:
main (void) {
main(10, "abc", 12.13);
// This throws "error: too many arguments to function ‘main’ "
}
C99报价
本回答旨在引用和解释C99 N1256标准草案的相关部分。
声明器的定义
声明器这个术语会经常出现,所以让我们来理解它。
从语言语法中,我们发现下面的下划线字符是声明符:
int f(int x, int y);
^^^^^^^^^^^^^^^
int f(int x, int y) { return x + y; }
^^^^^^^^^^^^^^^
int f();
^^^
int f(x, y) int x; int y; { return x + y; }
^^^^^^^
声明符是函数声明和定义的一部分。
有两种类型的声明器:
参数类型列表 标识符列表
参数类型列表
声明是这样的:
int f(int x, int y);
定义如下:
int f(int x, int y) { return x + y; }
之所以称为参数类型列表,是因为我们必须给出每个参数的类型。
标识符列表
定义如下:
int f(x, y)
int x;
int y;
{ return x + y; }
声明是这样的:
int g();
我们不能声明一个带有非空标识符列表的函数:
int g(x, y);
因为6.7.5.3“函数声明器(包括原型)”说:
函数声明器中不属于该函数定义的标识符列表应为空。
它被称为标识符列表,因为我们只给出f(x, y)上的标识符x和y,后面是类型。
这是一个较老的方法,不应该再使用了。6.11.6函数声明:
1使用带有空括号的函数声明器(而不是原型格式的参数类型声明器)是一个过时的特性。
引言解释了什么是过时的特性:
某些特性是过时的,这意味着它们可能会被考虑 在本国际标准的未来修订中撤回。它们被保留是因为 它们的广泛使用,但它们的使用在新的实现(为实现 特性)或新程序(针对语言[6.11]或库特性[7.26])是不鼓励的
F () vs F (void)用于声明
当你这样写时:
void f();
它必须是一个标识符列表声明,因为6.7.5“声明器”说将语法定义为:
direct-declarator:
[...]
direct-declarator ( parameter-type-list )
direct-declarator ( identifier-list_opt )
因此,只有标识符列表版本可以为空,因为它是可选的(_opt)。
直接声明器是唯一定义声明器圆括号(…)部分的语法节点。
那么,我们如何消除歧义和使用更好的参数类型列表没有参数?6.7.5.3函数声明符(包括原型)表示:
特殊情况下,void类型的未命名形参作为列表中唯一的项,指定该函数没有形参。
So:
void f(void);
就是这样。
这是一种神奇的语法,因为我们不能以任何其他方式使用void类型参数:
void f(void v);
void f(int i, void);
void f(void, int);
如果我使用f()声明会发生什么?
也许代码会编译得很好:6.7.5.3函数声明器(包括原型):
类的一部分,函数声明器中的空列表 类的数量或类型的信息 提供参数。
所以你可以逃避:
void f();
void f(int x) {}
其他时候,UB可能会爬行(如果你幸运的话,编译器会告诉你),你将很难弄清楚为什么:
void f();
void f(float x) {}
参见:为什么空声明适用于带有int参数的定义,而不适用于float参数?
F()和F (void)用于定义
f() {}
vs
f(void) {}
相似,但不完全相同。
6.7.5.3函数声明符(包括原型)表示:
函数声明器中的空列表是该函数定义的一部分,它指定该函数没有形参。
它看起来类似于f(void)的描述。
但仍…似乎是:
int f() { return 0; }
int main(void) { f(1); }
是遵循未定义的行为,而:
int f(void) { return 0; }
int main(void) { f(1); }
不符合:为什么gcc允许将参数传递给定义为无参数的函数?
TODO完全理解其中的原因。这和是不是原型有关系。定义原型。
除了语法上的差异,许多人还出于实际原因更喜欢使用void函数:
如果你正在使用搜索函数并想要找到函数的实现,你可以搜索function(void),它将返回原型以及实现。
如果省略void,则必须搜索function(),因此也将找到所有函数调用,从而使查找实际实现更加困难。