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() { /* ... */ }
对于所有托管实施均有效且可移植?
(请注意,我在C ++中既不解决也不void main
使用int main()
不带括号的问题。这只是int main(void)
和int main()
ISO C中的区别。)
没有。
根据标准的规范措辞,使用没有void
关键字的空括号的定义不是必须接受的形式之一,严格来说,这种程序的行为是不确定的。
参考:N1570第5.1.2.2.1节。(不是免费提供的已发布的2011 ISO C标准,其措辞与N1570草案相同。)
第1段说:
程序启动时调用的函数名为
main
。该实现没有为此函数声明任何原型。它的返回类型应为int
且不带参数:int main(void) { /* ... */ }
或带有两个参数(尽管可以使用任何名称,因为它们在声明它们的函数中是局部的,所以在这里称为
argc
和argv
,):int main(int argc, char *argv[]) { /* ... */ }
或同等学历; 或以其他一些实现定义的方式。
在约束之外使用单词“ 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%。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句