C++ main 函数

对于 C++ 中的 main() 函数,小伙伴们肯定再熟悉不过了,因为从第一个 C++ 程序开始我们就一直在和它打交道。学会如何编写自定义函数之后,这一节我们再来深入了解一下 main() 函数的运行细节与书写规范。

C++ main 函数简介

在 C++ 中,main() 函数也叫做 “主函数”,它是整个 C++ 程序的唯一入口。也就是说,不管一个程序有多少行代码、定义了多少个子函数,程序运行时总是从 main() 函数内部的第一行代码开始往下执行的。

很多初学的小伙伴会误以为 C++ 程序是从第一行的 #include <iostream> 开始执行的,实际上并非如此。

#include <iostream>

int main() {    // 程序从这里开始执行
    // 函数体
    return 0;
}

那最前面的 #include <iostream> 是什么时候起作用的呢?其实它是一条预处理指令,会在正式编译之前先把 <iostream> 里的 std::cout 等输入输出工具引入进来。关于预处理指令 #include 的细节,后面章节还会专门介绍。

可能有些小伙伴会问:“前面说函数只有在被调用的时候才会执行,为什么代码里只有 main() 的定义,却从来没见过调用 main() 的代码呢?”

这是因为普通函数需要由我们在代码里主动调用,而 main() 非常特殊,程序启动时会由操作系统自动找到并调用它。如果把整个 C++ 程序看成一辆汽车,main() 函数就相当于汽车的引擎,负责启动并带动各个子函数协同工作,如下图所示。

main() 函数驱动子函数协同工作

示例 1:main() 函数的执行顺序

#include <iostream>

void stepOne() {
    std::cout << "2. 执行 stepOne() 函数" << '\n';
}

int main() {
    std::cout << "1. 进入 main() 主函数" << '\n';
    stepOne();
    std::cout << "3. 回到 main() 并准备结束" << '\n';
    return 0;
}

运行结果如下。

1. 进入 main() 主函数
2. 执行 stepOne() 函数
3. 回到 main() 并准备结束

分析:

在这个例子中,stepOne() 虽然定义在文件最前面,但程序启动后依然直接从 main() 开始执行。程序先输出第 1 句话,接着调用 stepOne() 输出第 2 句话,最后跳回 main() 输出第 3 句话并结束。

对于 C++ 中的 main() 函数,我们可以总结出以下 4 个基本特点:

  • 一个完整的 C++ 程序必须有且只能有一个 main() 函数,并且 main() 不能被重载。
  • 无论程序里定义了多少个函数,运行时总是从 main() 函数开始执行。
  • main() 函数由操作系统在程序启动时自动调用,C++ 标准规定不能在程序内部手动调用或递归调用 main()。
  • main() 函数的返回类型必须是 int,用来向操作系统报告程序的退出状态。

main 函数的常见写法

在不同的教材或他人编写的代码中,我们经常会看到几种不同形式的 main() 函数。下面我们就来分清哪些是官方标准写法,哪些是需要避开的错误写法。

1. 两种官方标准写法

在 C++ 官方标准中,main() 函数主要有以下 2 种合法的标准写法:

// 方式 1
int main() {
    return 0;
}

// 方式 2
int main(int argc, char* argv[]) {
    return 0;
}

上面这两种方式都是完全符合 C++ 标准的:

  • 方式 1(无参形式):小括号内留空,表示不接收外部命令行参数,这是平时最常用的写法。在 C++ 中,int main() 与 C 语言风格的 int main(void) 完全等价,日常编写 C++ 代码我们直接写空括号 int main() 即可。
  • 方式 2(带参形式):当我们需要在命令行终端启动程序,并传入文件名等外部参数时使用。其中 argc 记录传入的参数个数,char* argv[] 用到了下一章将学习的指针与数组语法,用来存放各个参数的具体文本,现阶段先认个脸熟即可。

2. 返回类型不能写成 void

在一些早期教材或旧代码中,有时会看到把主函数写成 void main()。需要特别注意的是,C++ 官方标准从未允许过 void main() 这种写法,明确规定 main() 函数的返回类型必须是 int。正误写法对比如下:

// 正确方式
int main() {
    return 0;
}

// 错误方式
void main() {
}

注意 虽然极少数老旧编译器兼容 void main(),但在 GCC、Clang 等现代主流编译器中会直接报 '::main' must return 'int' 错误。编译器明确要求主函数必须返回 int,因此平时大家一定要统一写成 int main()。

C++ main 函数的返回值

对于普通子函数来说,函数返回值是返回给调用它的那行代码的。而 main() 函数是由操作系统调用的,因此 main() 的返回值其实就是交给操作系统的 “退出状态码”:

  • 返回 0:表示程序正常执行成功,整个过程没有发生错误。
  • 返回非 0 值:通常表示程序在运行过程中遇到了找不到文件、输入数据不合法等错误而异常退出,常见的错误返回值为 1。

普通子函数执行 return 只会结束当前子函数并回到调用处,而在 main() 主函数中间一旦执行了 return 语句,就代表整个程序到此执行完毕并立即退出。请看下面例子。

示例 2:在 main() 中提前退出

#include <iostream>

int main() {
    int count = -5;

    if (count < 0) {
        std::cout << "数量不能为负数,程序提前退出" << '\n';
        return 1;    // 返回错误码并提前退出
    }

    std::cout << "继续处理后续任务" << '\n';
    return 0;
}

运行结果如下。

数量不能为负数,程序提前退出

分析:

count < 0 条件成立后,程序进入 if 代码块打印提示信息,紧接着执行 return 1;。这句代码会把错误状态码 1 返回给操作系统并立即结束整个程序,因此后面的输出语句不会再执行。

此外,main() 还有一个区别于普通函数的特殊规则。返回 int 的普通函数必须显式写出 return 语句,唯独 main() 执行到函数体最末尾时,就算省略了 return 0;,编译器也会自动帮我们补上。也就是说,下面 2 种方式是等价的。

// 方式 1(推荐)
int main() {
    std::cout << "Hello, C++!" << '\n';
    return 0;
}

// 方式 2
int main() {
    std::cout << "Hello, C++!" << '\n';
}

在实际开发中,我们依然推荐小伙伴们采用方式 1,显式写上 return 0;,这样函数的首尾结构更加清晰完整。

main 函数外部的代码限制

在 C++ 源文件中,main() 以及其他函数的花括号 {} 外面并不是什么代码都能写的。在所有函数的外部,通常只允许编写以下 3 类声明或定义:

  • 使用 #include <iostream> 等预处理指令引入头文件。
  • 使用 int total = 0;、const double PI = 3.14; 等语句定义全局变量或全局常量。
  • 使用 int getSum(int a, int b); 声明函数,或者直接定义函数、结构体与类。

除了上述声明和定义之外,像 std::cout 输出语句、对已有变量重新赋值、if 条件判断、循环语句等具体的 “执行语句”,都必须放在 main() 或其他自定义函数的花括号 {} 内部,不能直接写在所有函数外面。

示例 3:在函数外部写执行语句

#include <iostream>

std::cout << "欢迎来到绿叶网!" << '\n';    // 非法操作

int main() {
    std::cout << 2026 << '\n';
    return 0;
}

运行结果如下。

(报错)error: 'cout' in namespace 'std' does not name a type

分析:

在这个例子中,我们尝试在 main() 函数外面直接使用 std::cout 输出一句话。由于编译器在所有函数外部只接受类型声明或变量、函数定义,结果发现 cout 并不是一个类型名,于是直接报出 does not name a type(不是一个类型名)错误。

小伙伴们只需要记住一条简单规则:函数外部只放引入头文件、定义全局变量、声明或定义函数这类 “准备工作”,真正干活的 “执行语句” 一律写进函数的花括号 {} 里面。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号