int main() { } (不带“void”)在 ISO C 中有效且可移植吗?

2024-03-02

C 标准指定了两种形式的定义main为一个 托管实施:

int main(void) { /* ... */ }

and

int main(int argc, char *argv[]) { /* ... */ }

它可以以与上述“等效”的方式定义(对于 例如,您可以更改参数名称,替换int通过 typedef 名称定义为int,或写char *argv[] as char **argv).

它也可以“以其他一些实现定义的方式”定义 ——这意味着像这样的事情int main(int argc, char *argv[], char *envp)有效if实施记录了它们。

“以其他实现定义的方式”条款不在 1989/1990 标准;它是由 1999 年标准添加的(但 早期的标准允许扩展,因此实现可以 仍然允许其他形式)。

我的问题是:鉴于当前(2011)ISO C 标准,是 形式的定义

int main() { /* ... */ }

对于所有托管实施都有效且可移植?

(请注意,我不是在解决void main或使用int main()C++ 中不带括号。这只是关于 之间的区别int main(void) and int main()在 ISO C 中。)


No.

根据标准的规范性措辞,定义 使用空括号而不使用void关键字不是其中之一 必须接受的形式,严格来说,行为 这样的程序是未定义的。

参考:N1570 http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf第 5.1.2.2.1 节。 (2011 年发布的 ISO C 标准,未 免费提供,措辞与 N1570 草案相同。)

第 1 段说:

程序启动时调用的函数名为main。实施声明没有 该函数的原型。它的返回类型应定义为int并且没有 参数:

int main(void) { /* ... */ }

或带有两个参数(此处称为argc and argv,尽管任何名称都可以是 使用,因为它们对于声明它们的函数来说是本地的):

int main(int argc, char *argv[]) { /* ... */ }

或同等学历;或者以其他一些实现定义的方式。

在约束之外使用“应”一词意味着任何 违反它的程序具有未定义的行为。例如,如果我写:

double main(unsigned long ocelots) { return ocelots / 3.14159; }

不需要符合标准的编译器来打印诊断信息,但它是 也不需要编译程序,或者如果确实编译了 它,让它以任何特定的方式表现。

If int main() were 相等的 to int main(void),那么它 对于任何符合要求的托管实现都是有效且可移植的。 但这并不等同。

int main(void) { }

提供了两个宣言(在本例中为原型)和定义。该声明通过使用void关键字,指定该函数没有参数。该定义指定了同样的事情。

如果我改为写:

int main() { }

然后我用的是老式声明和定义。 (这样的 声明和定义是过时的,但他们仍然 语言定义的一部分,所有符合标准的编译器必须 还是支持他们。)

作为声明,它不指定参数的数量或类型 函数所期望的。作为定义,它没有定义任何参数, 但编译器不需要使用该信息来诊断不正确的调用。

DR #317 http://www.open-std.org/jtc1/sc22/wg14/www/docs/dr_317.htm包括 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() is not相当于int main(void),因此 5.1.2.2.1 未涵盖。

结论:按照标准的措辞, 允许实施以记录int main() { }是 允许的。如果没有记录,仍然可以接受 毫无怨言。但符合标准的编译器也可能reject int main() { },因为它不是 允许的形式之一 标准,因此其行为是未定义的。

但仍然有一个悬而未决的问题:这是作者的意图吗? 标准的?

在 1989 年 ANSI C 标准发布之前,void关键字不存在。 Pre-ANSI (K&R) C 程序将定义main要么作为

main()

or as

int main()

ANSI 标准的一个主要目标是添加新功能(包括 原型)without破坏现有的 ANSI 之前的代码。说明int main()不再有效就会违反该目标。

我怀疑 C 标准的作者没有intend使int main()无效的。但书面标准并没有 反映该意图;至少它permits符合标准的 C 编译器 拒绝int main().

几乎说起来,你几乎肯定可以逃脱惩罚。 我尝试过的每个 C 编译器都会接受

int main() { return 0; }

没有抱怨,行为相当于

int main(void) { return 0; }

但由于多种原因:

  • 遵循标准的文字和意图;
  • 避免使用过时的功能(未来的标准可能会删除旧式的函数定义);
  • 保持良好的编码习惯(之间的区别() and (void)对于除此之外的功能很重要main实际上是由其他函数调用的)。

我建议总是写int main(void)而不是int main()。 它更清楚地表达了意图,您可以 100% 确定您的 编译器会接受它,而不是 99.9%。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

int main() { } (不带“void”)在 ISO C 中有效且可移植吗? 的相关文章

随机推荐