gpt4 book ai didi

c - int main() { }(没有 "void")在 ISO C 中有效且可移植吗?

转载 作者:太空狗 更新时间:2023-10-29 16:25:44 25 4
gpt4 key购买 nike

C 标准为 main 规定了两种形式的定义。为一个
托管实现:

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


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

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

它也可以“以某种其他实现定义的方式”定义
-- 这意味着诸如 int main(int argc, char *argv[],
char *envp)
之类的东西如果实现记录了它们,则它们是有效的。

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

我的问题是:鉴于当前 (2011) ISO C 标准,是
表格的定义
int main() { /* ... */ }

对所有托管实现有效且可移植?

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

最佳答案

不。

根据标准的规范性措辞,定义
使用不带 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.



在约束之外使用“应”一词意味着任何
违反它的程序具有未定义的行为。因此,例如,如果我写:
double main(unsigned long ocelots) { return ocelots / 3.14159; }

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

int main()相当于 int main(void) ,那么它
对任何符合要求的托管实现都是有效的和可移植的。
但这不是等价的。
int main(void) { }

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

如果我改为写:
int main() { }

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

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

DR #317包括 C 标准委员会 2006 年的裁决,即定义为 ()不提供与 (void) 等效的原型(prototype)(感谢 hvd 找到该引用)。

C 允许 main被递归调用。假设我写:
int main(void) {
if (0) {
main(42);
}
}

可见原型(prototype) 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关键字不存在。 Pre-ANSI (K&R) C 程序将定义 main要么作为
main()

或作为
int main()

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

我的怀疑是 C 标准的作者并不打算
制作 int main()无效的。但是书面标准没有
反射(reflect)该意图;它至少允许符合标准的 C 编译器
拒绝 int main() .

实际上,您几乎可以肯定会侥幸逃脱。
我试过的每个 C 编译器都会接受
int main() { return 0; }

无怨无悔,行为相当于
int main(void) { return 0; }

但出于多种原因:
  • 遵循标准的文字和意图;
  • 避免使用过时的功能( future 的标准可能会删除旧式的函数定义);
  • 保持良好的编码习惯(()(void) 之间的区别对于main 以外的其他函数实际调用的函数很重要)。

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

    关于c - int main() { }(没有 "void")在 ISO C 中有效且可移植吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29190986/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com