哪个更好: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(),因此也将找到所有函数调用,从而使查找实际实现更加困难。