很多人甚至市面上的一些书籍,都使用了void main( ) ,其实这是错误的。C/C++ 中从来没有定义过void main( ) 。C++ 之父 Bjarne Stroustrup 在他的主页上的 FAQ 中明确地写着 The definition void main( ) { /* ... */ } is not and never has been C++, nor has it even been C.( void main( ) 从来就不存在于 C++ 或者 C )。下面我分别说一下 C 和 C++ 标准中对 main 函数的定义。

1. C

在 C89 中,main( ) 是可以接受的。Brian W. Kernighan 和 Dennis M. Ritchie 的经典巨著 The C programming Language(《C 程序设计语言》)用的就是 main( )。不过在最新的 C99 标准中,只有以下两种定义方式是正确的:

int main( void )

int main( int argc, char *argv[] )

(参考资料:ISO/IEC 9899:1999 (E) Programming languages — C 5.1.2.2.1 Program startup)

当然,我们也可以做一点小小的改动。例如:char *argv[] 可以写成 char **argv;argv 和 argc 可以改成别的变量名(如 intval 和 charval),不过一定要符合变量的命名规则。

如果你不需要从命令行中获取参数,请用 int main( void ) ;否则请用 int main( int argc, char *argv[] ) 。

main 函数的返回值类型必须是 int ,这样返回值才能传递给程序的激活者(如操作系统)。

如果 main 函数的最后没有写 return 语句的话,C99 规定编译器要自动在生成的目标文件中(如 exe 文件)加入 return 0 ,表示程序正常退出。不过,我还是建议你最好在 main 函数的最后加上 return 语句,虽然没有这个必要,但这是一个好的习惯。注意,vc6 不会在生成的目标文件中加入 return 0 ,大概是因为 vc6 是 98 年的产品,所以才不支持这个特性。现在明白我为什么建议你最好加上 return 语句了吧!不过,gcc3.2(Linux 下的 C 编译器)会在生成的目标文件中加入 return 0 。

2. C++

C++98 中定义了如下两种 main 函数的定义方式:

int main( )

int main( int argc, char *argv[] )

(参考资料:ISO/IEC 14882(1998-9-01)Programming languages — C++ 3.6 Start and termination)

int main( ) 等同于 C99 中的 int main( void ) ;int main( int argc, char *argv[] ) 的用法也和 C99 中定义的一样。同样,main 函数的返回值类型也必须是 int 。如果 main 函数的末尾没写 return 语句,C++98 规定编译器要自动在生成的目标文件中加入 return 0 。同样,vc6 也不支持这个特性,但是 g++3.2(Linux 下的 C++ 编译器)支持。

3. 关于 void main

在 C 和 C++ 中,不接收任何参数也不返回任何信息的函数原型为“void foo(void);”。可能正是因为这个,所以很多人都误认为如果不需要程序返回任何信息时可以把 main 函数定义成 void main(void) 。然而这是错误的!main 函数的返回值应该定义为 int 类型,C 和 C++ 标准中都是这样规定的。虽然在一些编译器中,void main 可以通过编译(如 vc6),但并非所有编译器都支持 void main ,因为标准中从来没有定义过 void main 。g++3.2 中如果 main 函数的返回值不是 int 类型,就根本通不过编译。而 gcc3.2 则会发出警告。所以,如果你想你的程序拥有很好的可移植性,请一定要用 int main 。

4. 返回值的作用

main 函数的返回值用于说明程序的退出状态。如果返回 0,则代表程序正常退出,否则代表程序异常退出。下面我们在 winxp 环境下做一个小实验。首先编译下面的程序:

int main( void )

{

return 0;

}

然后打开附件里的“命令提示符”,在命令行里运行刚才编译好的可执行文件,然后输入“echo %ERRORLEVEL%”,回车,就可以看到程序的返回值为 0 。假设刚才编译好的文件是 a.exe ,如果输入“a && dir”,则会列出当前目录下的文件夹和文件。但是如果改成“return -1”,或者别的非 0 值,重新编译后输入“a && dir”,则 dir 不会执行。因为 && 的含义是:如果 && 前面的程序正常退出,则继续执行 && 后面的程序,否则不执行。也就是说,利用程序的返回值,我们可以控制要不要执行下一个程序。这就是 int main 的好处。如果你有兴趣,也可以把 main 函数的返回值类型改成非 int 类型(如 float),重新编译后执行“a && dir”,看看会出现什么情况,想想为什么会出现那样的情况。顺便提一下,如果输入 a || dir 的话,则表示如果 a 异常退出,则执行 dir 。

int main( int argc, char *argv[], char *env[] ) 也不是标准C里面定义的东西~char *env[]是某些编译器提供的扩展功能~用于获取系统的环境设定~因为不是标准~故而移植性差~不推荐使用

本文版权归 蚂蚁的 C/C++ 标准编程 以及 作者 antigloss 共同所有,转载请注明原作者和出处。谢谢。

C/C++语言误区void main( )的更多相关文章

  1. 「C语言」int main还是void main?

    从大一入学刚接触C到现在已满7个月了,虽然刚开始就知道```int main```才是标准的写法,但一直没有深刻理解为什么不能用```void main```而必须使用```int main```. ...

  2. 关于void main()的误区

    很多人甚至市面上的一些书籍,都使用了void main( ) ,其实这是错误的.C/C++ 中从来没有定义过void main( ) .C++ 之父 Bjarne Stroustrup 在他的主页上的 ...

  3. int main()还是void main()

    按照新的C99标准,即使函数本身没有定义返回值,编译器也会加上,以返回给激发程序,运行状态.很多人甚至市面上的一些书籍,都使用了void main( ) ,其实这是错误的.C/C++ 中从来没有定义过 ...

  4. C语言编程漫谈——main函数

    写在前面 促使我写这篇文章是因为我这几天找了几个一样是大三的同学,与我相同专业相同方向(物联网)的人,除了@小胡同的诗,基本没有什么其他人会现在看起来很简单的编程题目了.问了一下其他同学,他们大部分都 ...

  5. C/C++ 下的void main()

    很多人甚至市面上的一些书籍,都使用了void main( ),其实这是错误的.C/C++ 中从来没有定义过void main( ).C++之 父 Bjarne Stroustrup在他的主页上的 FA ...

  6. java里面的public static void main(String[] args)

    package com.java_1; public class Hello { public static void main(String[] args){ System.out.println( ...

  7. java中public static void main(String[] args)中String[] args代表什么意思?

    这是java程序的入口地址,java虚拟机运行程序的时候首先找的就是main方法.跟C语言里面的main()函数的作用是一样的.只有有main()方法的java程序才能够被java虚拟机欲行,可理解为 ...

  8. JAVA:从public static void main(String args[])開始

    我们都知道当你要执行一个JAVA文件的时候必需要有一个main函数. 这是为什么呢? 跟C语言的道理一样,当你执行一个文件的时候.你必需要有一个入口函数或者入口地址,在C里面是main函数.相同的在J ...

  9. void main() && int main()

    C/C++ 中从来没有定义过void main( ) .C++ 之父说过: The definition void main( ) { /* ... * / } is not and never ha ...

随机推荐

  1. (七十八)c#Winform自定义控件-倒影组件

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. GitHub:https://github.com/kwwwvagaa/NetWinformControl 码云:ht ...

  2. Spring boot 梳理 - 模版引擎 -freemarker

    开发环境中关闭缓存 spring: thymeleaf: cache: false freemarker: cache: false Spring boot 集成 freemarker <dep ...

  3. Linux环境下实现对文件读写操作

    ---- 今天分享一下在linux系统在实现对文件读写一些基本的操作,在这之前我们要掌握一些基本的技能在Linux环境下.比如查看命令和一个函数的具体用法,就是相当于查手册,在Linux下有一个man ...

  4. javascript中数组常用的方法和属性

    前言 在javascript中,数组是一种非常重要的数据类型,我们时常会和它打交道,最近在开发项目中频繁的使用到数组,但是自己对数组的众多方法已经是非常模糊了,为了方便自己以后能够更好的使用数组中的属 ...

  5. ArchLinux安(重)装指南

    说实话,我其实是不想要出这篇博客的.在我这一个月安装Arch的过程中,让我感触比较深的一点是: 没有谁比这个系统的官方更懂它. 尤其是这种比较复杂的系统,更是如此. 这几天,我经历了一次重装,系统坏了 ...

  6. EF Core 实现读写分离的最佳方案

    前言 公司之前使用Ado.net和Dapper进行数据访问层的操作, 进行读写分离也比较简单, 只要使用对应的数据库连接字符串即可. 而最近要迁移到新系统中,新系统使用.net core和EF Cor ...

  7. .Net Core 商城微服务项目系列(八):购物车

    最近加班有点多,一周五天,四天加班到11点+,心很累.原因是我当前在的这个组比较特殊,相当于业务的架构组,要为其它的开发组提供服务和监控.所以最近更新的也少,不过这个元旦三天假应该会更新三篇. 这篇是 ...

  8. MongoDB安装过程中出现service MongoDB failed to start,verify that you have sufficient privileges to start...

    win10系统下,安装MongoDB 64位, service MongoDB failed to start,verify that you have sufficient privileges t ...

  9. Redis开发与运维:数据迁移

    问题 最近项目重构,提前想把一台上的redis实例转移到另一台redis实例上. 源redis数据库:阿里云Redis.VPC网络.Server版本2.8.19 目标数据库:阿里云Redis.VPC网 ...

  10. java中不创建使用第三方变量,交换两个数的值

    1.直接使用算术运算法交换 先把两个数的和赋值给其中一个,然后做减法.例如num1=num1+num2; 此时num2(交换之后)就等于num1减去num2:废话不多说,直接上代码 public cl ...