对于 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() 函数就相当于汽车的引擎,负责启动并带动各个子函数协同工作,如下图所示。

示例 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(不是一个类型名)错误。
小伙伴们只需要记住一条简单规则:函数外部只放引入头文件、定义全局变量、声明或定义函数这类 “准备工作”,真正干活的 “执行语句” 一律写进函数的花括号 {} 里面。
