快速入门

写出你的第一个 C++ 程序,理解从敲下源码到跑出结果之间发生了什么。

学习目标

  • 能用自己的话解释 C++ 源码从敲下到跑出结果,中间经过了哪四道工位,以及每道工位做了什么
  • 能解释一个最简 C++ 程序中 #includemaincoutreturn 各自在干什么
  • 能回答:如果把 return 0; 删掉,程序还能跑吗?删掉 #include <iostream> 呢?

为什么写下了代码,电脑就能懂?

你敲下一段 C++ 代码,点运行,屏幕上就出现了一行 "Hello, World!"。这正是官方首节 Writing a Simple C++ Program(编写简单 C++ 程序)的任务。这中间其实经过了一条工厂流水线——你的代码是「原料」,经过几道工位一道道加工,最后从流水线另一头出来一个能直接运行的「成品」。

这条流水线有四道工位:第一道把原料里杂七杂八的标注清理干净、展开折叠好的部分;第二道把人类能读的文字翻译成机器"方言";第三道把方言逐字译成机器能认的二进制编码;第四道把分散的零件拼成一个完整的、能直接跑的程序。

这一章就带你走一遍这条流水线的四道工位,同时写出你人生中第一个 C++ 程序。没有这条流水线会怎样?你写的代码永远只是一堆人类能读的文字,电脑一个字也不认识。

你的第一个程序,逐行拆开看

在走流水线之前,先把「原料」长什么样搞清楚。下面这个六行代码就是 C++ 里最经典的一小段:

hello.cpp1#include <iostream>3int main() {4 std::cout << "Hello, World!" << std::endl;5 return 0;6}包含头文件:让你能用 coutmain 函数:程序从这里开始执行cout:往控制台输出文字return 0:告诉操作系统「程序正常结束」一个最简 C++ 程序:包含头文件、定义 main 入口、用 cout 输出、return 返回
一个最简 C++ 程序的四个关键部分:头文件声明能力、main 函数指定入口、 cout 把文字送到控制台、return 返回执行状态给操作系统。

每一行都在说什么?下面逐一看。

main 函数:程序从这进门

是整个程序的入口。你写再多代码,操作系统启动你的程序时都只会钻进 main 这个大门。int 表示它最后要交回一个整数,「交给操作系统」——return 0 就是在说「一切正常,我跑完了」。如果把 return 0 删掉?现代编译器一般会自己帮你补一句,但规范上每一扇大门走了就要把"我没事"的纸条留下来。

它处在整个流程的起点:你的所有代码都经过它开始执行,它是流水线前那道「开工」的指令。

头文件:声明"我能用什么"

代码第一行 #include <iostream> 是什么?它是一句 iostream 这个头文件里写好了 cin(从键盘读输入)和 cout(往屏幕写输出)的声明。你不 include 它就直接写 cout,编译器会告诉你「我不认识 cout 是什么东西」。

它处在流水线的第一道工位(预处理):预处理器看到 #include,就把那个文件里的所有文字原样粘贴到你这行所在的地方。之后你再引用 cout,编译器才知道「哦,原来这个东西在 iostream 里定义过」——预处理这一步之后继续往下走。

std::cout << "Hello, World!" << std::endl; 是本文真正干活的一句——把 "Hello, World!" 这段文字送进 cout 输出流,再补一个换行 std::endl,于是屏幕上就出字了。std::——可以理解成「住在 std 这个门牌号下的 cout」。在它前面加上 std::,就是在告诉编译器「我用的是 std 空间里的那个 cout,不是别的」。

它和 main 函数里余下的语句,在编译流程中对应第二道和第三道工位:编译器先把这行 C++ 语法解析成汇编指令,汇编器再把它变成二进制机器码。

什么是「流」——cin 和 cout 在干什么

coutcin 都是一种叫 的东西。想象两条管道:cout 是通往屏幕的那根水管,你用 << 把文字往里一塞,它就顺着管道流到控制台窗口显示出来。反过来,cin 是从键盘那边过来的水管,你用 >> 往外抽数据,像用吸管从杯子里吸水。

<< 把右边的数据推向左边那条流管道,>> 则相反。它们背后有缓冲区暂存,数据并不是一个字一个字立刻上屏——等缓冲区满了或遇到 endl,一整批一起推过去,减少来回奔波。下面这张图把两条管道的方向画出来:

键盘输入设备cin输入流(读)stdin 缓冲区你的程序处理·计算int main()cout输出流(写)stdout 缓冲区控制台屏幕显示>>#include <iostream> 让程序拥有「管道」能力——用 cin 读、用 cout 写输入方向 ←处理输出方向 →
键盘通过 cin 输入流把数据送进程序,程序通过 cout 输出流把结果送到控制台。 流经过缓冲区暂存,用 << 和 >> 运算符来「送」数据。

流在整个流程里不归属某一道工位——它是运行时才工作的概念。编译流水线只是造出了程序的「外壳」;等到你双击运行,cin/cout 这套管道才真正开始流动。

从控制流走到书店程序

官方 Chapter 1 不止写一个 Hello World。Flow of Control 让程序能重复读取未知条数的交易,并按条件决定继续累计还是输出;Introducing ClassesSales_item 展示“先使用类的接口,再理解实现”;最后的 The Bookstore Program 把这些能力接成完整数据处理流程。

首先体现在 while (std::cin >> item):输入成功时条件为真,循环处理当前交易;遇到 EOF 或格式错误时 stream 状态变为失败,循环自然停止。if (total.isbn() == item.isbn()) 再决定合并同一本书,还是先输出上一组并开始新组。

让调用者只关心 isbn()、输入、输出和 +=,不必先知道数据成员如何存储。这个顺序体现第五版的 C++11 教学取向:从一开始使用标准库和抽象类型,而不是先陷入字符数组和手工内存。

Sales_item total;
if (std::cin >> total) {
    Sales_item item;
    while (std::cin >> item) {
        if (total.isbn() == item.isbn()) total += item;
        else { std::cout << total << '\n'; total = item; }
    }
    std::cout << total << '\n';
}

这段程序还建立了后续章节的阅读方法:先写清输入 contract,使用类型公开接口完成业务,再用控制流组织生命周期,最后以编译、运行和样例输出验收。Chapter 1 的完成标准因此是“能处理一组交易”,不是只看到终端打印一句话。

注释:给自己和队友留话

代码里双斜线 // 开头的那一行、或者 /**/ 裹起来的那一段,叫 。它们写给未来看这行代码的人——包括三个月后的你自己。预处理器在第一道工位就把注释剥光了(替换成空格),它们一个字都不会进最终的二进制程序,所以想写多少写多少。

// 只能管到行末;/* */ 能跨行包住一大段。比较:

// 这是一个单行注释——只到这一行末尾
std::cout << "hi"; // 也可以写在语句后面
 
/* 这是一个多行注释——
   可以跨好几行,
   裹住一大片 */

注释不占用运行时任何资源,因为它们走完预处理就从代码里消失了——在第一道工位,/* */ 形式的注释有时甚至被预处理器直接替换成空格。

动手:跟着编译器走一遍流水线

现在你知道了每行代码在说什么,下面打开这条流水线,一步步看你的代码怎么变成能跑的程序。下面这个分步演示把一个 hello.cpp 从源码走完四道工位——每切一步,上面的流程图会高亮当前工位,下方说明这一步发生了什么

猜一猜:哪一道工位最耗时?是把头文件展开、还是把 C++ 翻译成汇编?动手切一切,看看每一步的解释再说你的答案。

分步1 / 4

① 预处理:把 #include、#define 都展开

.cpp源码1预处理宏展开·头文件#include→展开#define→替换2编译C++→汇编语法检查生成 .s3汇编汇编→机器码生成 .o目标文件4链接合并·解析符号多 .o + 库→ 可执行文件.cpp.i.s.oexe把头文件内容「粘贴」进来,把宏展开成代码,生成纯净的 .i 文件
C++ 编译流水线:源码 .cpp 经过预处理、编译、汇编、链接四道工位,最终产出可执行文件。 本章 Stepper 分步讲解每道工位具体做了什么。

预处理器先打开你的 hello.cpp。它做三件事:① 见到 #include <iostream>,就把整个 iostream 文件内容原样粘贴进来(可能有几千行);② 见到 #define 宏就把所有用到的地方替换掉;③ 删掉所有注释。输出的是一个「展开过的纯净源代码」——后缀名 .i。你可以理解成:把原料里折叠的、注解的部分全摊平,得到一张干干净净的底稿。

代码速查:一行命令走完流水线

不用 IDE 点按钮,直接在终端里敲一条命令,就能从头到尾跑完上面那四道工位。以 Linux/macOS 上的 g++ 为例:

# 一条命令 = 预处理 + 编译 + 汇编 + 链接
g++ hello.cpp -o hello
 
# 运行你刚造出来的程序
./hello
# 输出:Hello, World!

如果你好奇中间产物的样子,可以分步走:

# 只预处理,看展开的头文件有多长
g++ -E hello.cpp -o hello.i
 
# 只编译成汇编,看 C++ 语句被翻译成什么
g++ -S hello.cpp -o hello.s
 
# 只汇编成目标文件(二进制,人类不可读)
g++ -c hello.cpp -o hello.o

在 Visual Studio 下,按 Ctrl+F5 运行;Xcode 里点 Product → Run。IDE 背后做的事完全一样。

容易踩的坑

小结

  • C++ 源码经过四道工位变成可执行文件:预处理→编译→汇编→链接
  • int main() 是程序入口,return 0 告诉操作系统「一切正常」
  • #include 在预处理阶段把头文件内容粘贴进来,让你能使用 cin/cout
  • cout << 把数据推进输出流送到屏幕,cin >> 从输入流取出键盘输入——背后有缓冲区暂存
  • 注释 ///* */ 写给程序员看,编译器在处理时完全忽略它们

练习

问题 1(改代码型) 把上面 Hello World 程序里的 "Hello, World!" 改成 "你好,C++!",再加一行 std::cout << "这是我的第一个程序。" << std::endl;。在 return 0; 之前加一句 std::cin.get(); 让窗口停住。跑起来,解释你加的每一句各干了什么。

问题 2(问答型) 编译流水线的四道工位如果出一道错,分别会长什么样?各举一个例子。

问题 3(问答型)#include <iostream> 删掉,程序还能编译吗?把这行注释掉试试(用 //),把你看到的错误信息抄下来,解释编译器为什么报这个错。

名词解释

本章出现的专业名词,用大白话再讲一遍。

main 函数

C++ 程序的入口。操作系统运行你的程序第一件事就是钻进 main,从它开始一行一行往下跑。int 表示它会交回一个整数给操作系统,return 0 就是说「正常结束了」。详见本章「main 函数」一节。

头文件

#include 拉进来的文件,里面写好了别人为你准备好的东西的声明。比如 <iostream> 里声明了 cincout——你不是自己写它们怎么工作,而是 include 后直接用。它在预处理阶段被「粘贴」进你的源码。详见本章「头文件」一节。

语句

程序里一个独立操作单元。多数 C++ 语句以分号 ; 结束,表达「这句话说完了,可以执行下一句」。int x = 1;cout << "hi"; 都是语句。

命名空间

一群相关名字的「门牌号」。std 是 C++ 标准库住的那个门牌号——std::cout 意思是「std 门牌号下的那个 cout」。加上门牌号,不同库里即使起了同样的名字也不会打架。详见本章「头文件」一节。

流(stream)

把数据想象成水,流就是它的通道。cout 是通向屏幕的「输出流管道」,用 << 把数据往里一塞就顺管流到控制台。cin 是从键盘过来的「输入流管道」,用 >> 往外抽数据。管道两头有缓冲池暂存,满了或遇到 endl 才一口气推过去。详见本章「什么是流」一节。

输出运算符

<< 符号在 cout << x 里不是「向左移位」,而是被重新赋予了含义:把右边的东西推进左边那根流管道。同理 cin >> x>> 是「从左边管道里拉东西出来给右边」。二者都是对同一个符号赋予了与人读的直觉一致的语义。详见本章「什么是流」一节。

控制流

决定程序下一步执行哪条语句的结构。本章用输入流状态驱动 while,再用 ISBN 比较驱动 if/else,从而处理任意数量的书店交易。

Sales_item 类

原书第一章用于表示一条书店交易的类,通过输入输出、isbn()+= 接口演示如何先使用抽象类型,再学习类的内部实现。

注释

代码里写给程序员看的文字,编译器完全忽略。// 是单行注释(本行到此完),/* */ 是多行注释(中间全忽略)。给三个月后的自己留句话,别全靠记忆力。详见本章「注释」一节。

资料与写作方式声明

本章以C++ Primer, Fifth Edition, Chapter 1: Getting Started权威目录界定学习范围,并结合正文列出的技术资料独立重写;不宣称复现原书正文,也不沿用原作表述。

原作版权归作者与出版社所有;本站原创教学结构与表述仅供学习交流。

讨论

评论区加载中…