int main(){}(无“ void”)在ISO C中是否有效且可移植?

基思·汤普森

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) { /* ... */ }

或带有两个参数(尽管可以使用任何名称,因为它们在声明它们的函数中是局部的,所以在这里称为argcargv,):

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] 删除。

编辑于
0

我来说两句

0条评论
登录后参与评论

相关文章

来自分类Dev

“ void main”和“ int main”之间的区别

来自分类常见问题

是'int main;' 有效的C / C ++程序?

来自分类Dev

无符号int向量c ++

来自分类Dev

C ++中有符号或无符号int

来自分类Dev

C ++中有符号或无符号int

来自分类Dev

void main(void)是否正确?

来自分类Dev

`int main(int argc,char * argv <::>)`是main的有效签名吗?

来自分类Dev

在将main声明为int main(void)时,为什么在传递命令行参数时没有错误?

来自分类Dev

在无符号int中存储负数

来自分类Dev

ISO C ++禁止声明无类型的“参数”

来自分类Dev

ISO C ++禁止声明无类型的“向量”

来自分类Dev

ISO C ++禁止声明无类型的“某物”

来自分类Dev

ISO C ++禁止声明无类型的“向量”

来自分类Dev

int main的返回码-是否有上限?

来自分类Dev

从main访问void中的变量

来自分类Dev

从main访问void中的变量

来自分类Dev

C ++有符号和无符号int与长而长的速度

来自分类Dev

C 中的 main 函数,有 void 和没有 void

来自分类Dev

无符号的int值

来自分类Dev

C中的无符号Int到RGB值

来自分类Dev

C ++在无符号long long int值中的奇怪跳转

来自分类Dev

C中无符号long和int的加法

来自分类Dev

int main(int argc,char ** argv)与c中的<stdin> stdout

来自分类Dev

通过套接字发送int:有符号与无符号

来自分类Dev

添加有符号和无符号int

来自分类Dev

通过套接字发送int:有符号与无符号

来自分类Dev

int转换为Java中的无符号char数组

来自分类Dev

C ++无符号短裤的除法结果为int

来自分类Dev

将无符号字符转换为 int C++