C标准为main指定了两种定义形式
托管实现:

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


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

可以按照与上述“等同”的方式定义
例如,您可以更改参数名称,用typedef替换int名称定义为int,或将char *argv[]写为char **argv)。

也可以“以某些其他实现定义的方式”定义它
-这意味着如果int main(int argc, char *argv[],char *envp)之类的东西在实现文档中说明是有效的。

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

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

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

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

最佳答案

没有。

根据标准的规范措辞,定义
使用不带void关键字的空括号不是其中一种
必须接受的表格,严格来说是
这样的程序是不确定的。

引用:
N1570
5.1.2.2.1节。 (已发布的2011 ISO C标准
免费提供,其措辞与N1570草案相同。)

第1段说:



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

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);
    }
}

可见的int main(void)原型(prototype)指定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标准的主要目标是添加新功能(包括
原型(prototype))而不会破坏现有的pre-ANSI代码。说明int main()不再有效,将违反该目标。

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

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

无投诉,行为等同于
int main(void) { return 0; }

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

  • 我建议始终编写int main(void)而不是int main()
    它可以更清楚地说明意图,您可以100%确保
    编译器将接受它,而不是99.9%。

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

    10-11 23:01
    查看更多