不可以。
根据标准的规范措辞,使用空括号而没有 void
关键字的定义不是必须接受的形式之一,严格来讲这种程序的行为是未定义的。
参考文献:
N1570
第5.1.2.2.1节。(2011年发布的ISO C标准不免费提供,其措辞与N1570草案相同。)
第1段说:
The function called at program startup is named main
. The implementation declares no
prototype for this function. It shall be defined with a return type of int
and with no
parameters:
int main(void) { }
or with two parameters (referred to here as argc
and argv
, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { }
or equivalent; or in some other implementation-defined manner.
在约束之外使用“shall”这个词意味着任何违反它的程序都有未定义的行为。因此,例如,如果我写:
double main(unsigned long ocelots) { return ocelots / 3.14159; }
一个符合规范的编译器不一定需要输出诊断信息,但也不需要编译程序或者如果编译了程序,则不需要以任何特定的方式运行它。
如果
int main()
等同于
int main(void)
,那么它将是有效且可移植到任何符合规范的托管实现。但它们并不等价。
int main(void) { }
提供了一个声明(在本例中为原型)和一个定义。通过使用 void
关键字,声明指定函数没有参数。定义也指定了同样的内容。
如果我改为以下写法:
int main() { }
那么我使用的是旧式声明和定义。(这些声明和定义已经过时,但它们仍然是语言定义的一部分,并且所有符合标准的编译器仍必须支持它们。)
作为一个声明,它没有指定函数期望的参数数量或类型。作为一个定义,它不定义参数,但编译器不需要使用该信息来诊断不正确的调用。
DR #317 包括 C 标准委员会在 2006 年做出的裁决,即带有 ()
的定义不能提供等同于带有 (void)
的原型(感谢 hvd 找到该参考文献)。
C 允许递归调用 main
。假设我写:
int main(void) {
if (0) {
main(42);
}
}
可见的原型int main(void)
指定了main
不接受任何参数。试图传递一个或多个参数的调用会违反约束条件,需要在编译时进行诊断。
或者假设我写:
int main() {
if (0) {
main(42);
}
}
如果执行调用
main(42)
,它将具有未定义的行为--但它不违反约束,并且不需要诊断。由于受到
if (0)
保护,因此从未发生调用,也从未实际发生未定义的行为。如果我们假设
int main()
是有效的,则该程序必须被任何符合规范的编译器接受。但正因为如此,它证明了
int main()
并非等同于
int main(void)
,因此不受5.1.2.2.1的覆盖。
结论:根据标准的措辞,实现可以记录
int main() { }
是允许的。如果没有记录,仍然可以接受它而不会抱怨。但符合规范的编译器也可能拒绝
int main() { }
,因为它不是标准允许的形式之一,其行为因此未定义。
但仍有一个未解决的问题:这是否是标准作者的意图?
在1989年 ANSI C 标准发布之前,不存在
void
关键字。 ANSI 之前的(K&R)C 程序将会定义
main
为以下之一:
main()
或者作为
int main()
ANSI标准的一个主要目标是在不破坏现有的ANSI之前的代码的情况下添加新功能(包括原型)。声称
int main()
不再有效将违反该目标。
我怀疑C标准的作者们并没有打算使
int main()
无效。但是,按照所写的标准并没有体现出这种意图;它至少允许符合C编译器拒绝
int main()
。
实际上,你几乎肯定可以使用它。我尝试过的每个C编译器都会接受。
int main() { return 0; }
不抱怨,行为相当于
int main(void) { return 0; }
但出于各种原因:
- 遵循标准的文字和意图;
- 避免使用过时的特性(未来的标准可能会删除旧式函数定义);
- 保持良好的编码习惯(对于实际被其他函数调用的函数而言,
()
和(void)
之间的区别非常重要,不仅仅是main
函数)。
我建议始终编写int main(void)
而不是int main()
。
它更清晰地表明了意图,并且您可以100%确定您的
编译器将接受它,而不是99.9%。