一:为什么学 C/C++——两门统治底层世界的语言

一、你已经站在了一个很好的起点上

如果你已经跟完了《前端圭臬》《后端零基础入门》《Python 零基础入门》这三个系列,你现在手里至少有两把刷子:

  • JavaScript:动态类型、解释执行、事件驱动。前端用它写页面交互,Node.js 用它写后端服务。
  • Python:动态类型、解释执行、语法简洁。爬虫、数据分析、自动化脚本、Flask 后端,都能搞定。

这两门语言有一个共同点:它们都是高级语言,离计算机硬件比较远。你不需要关心内存怎么分配、变量存在哪里、CPU 怎么执行指令——这些细节都被语言的运行时环境帮你处理好了。

但如果你想理解计算机的底层运作机制,想知道操作系统是怎么管理内存的,想写出高性能的计算密集型程序,或者想进入嵌入式、游戏开发、音视频处理等领域,就需要一门更接近硬件的语言。这就是 C 和 C++ 的领域。

学会 C/C++,你会对之前学过的所有语言有一个全新的理解——你会明白 JavaScript 的变量是怎么存在内存里的、Python 的对象到底在堆上还是栈上、为什么有些操作快有些操作慢。

二、C 和 C++ 到底是什么关系

很多人把 C 和 C++ 混在一起说,但它们并不是同一门语言。它们的关系可以用一句话概括:C++ 是 C 的超集,但也是独立的一门语言。

C 语言(1972 年)

C 语言诞生于贝尔实验室,最初是为了写 Unix 操作系统而设计的。它的设计哲学是:相信程序员,提供最少的抽象,把性能控制权交给开发者。

C 语言的特点:

  • 面向过程:程序由一个个函数组成,数据和操作数据的方法是分开的。没有类、没有对象、没有继承。
  • 极简:C 语言的核心关键字只有 32 个,标准库很小。你写的代码非常接近机器实际执行的指令。
  • 手动管理内存:你需要自己申请内存、自己释放内存。没有垃圾回收机制。写得好,程序飞起;写不好,内存泄漏和野指针会折磨你。
  • 指针:C 语言最强大的特性,也是最令人头疼的特性。指针让你直接操作内存地址,这是高级语言不敢给开发者的能力。

如今,C 语言主要用于:操作系统内核、驱动程序、嵌入式系统、单片机、以及任何需要直接和硬件打交道的地方。

C++(1985 年)

C++ 最初的名字叫“C with Classes”(带类的 C)。它在 C 语言的基础上增加了面向对象的特性:类、对象、继承、多态。之后的几十年里,C++ 不断添加新特性——模板、STL(标准模板库)、Lambda 表达式、智能指针。

C++ 的设计哲学是:你可以选择任何编程范式——面向过程、面向对象、泛型编程、函数式编程——都在同一门语言里。

C++ 的特点:

  • 兼容 C:大部分合法的 C 代码也是合法的 C++ 代码。你可以混用两种风格。
  • 面向对象:类、封装、继承、多态。这让代码的组织和复用能力远超 C。
  • 泛型编程:模板机制让你可以写出适用于任意类型的代码。C++ 标准库中的 vectormap 等都是模板类。
  • RAII(资源获取即初始化):C++ 独有的资源管理哲学,用对象的生命周期来管理内存、文件、锁等资源。这是现代 C++ 最核心的设计理念。
  • 零开销抽象:你不用的特性,不会增加运行时开销。这是 C++ 和 Java/C# 等语言的根本区别。

如今,C++ 主要用于:游戏引擎(虚幻引擎)、浏览器内核(Chrome 的 Blink 引擎)、数据库(MySQL)、音视频处理(FFmpeg)、金融交易系统、以及任何对性能有极致要求的场景。

一张对比表

特性 C C++
编程范式 面向过程 多范式(面向过程、面向对象、泛型)
类和对象 没有
模板/泛型 没有 有(template)
标准库 小而精 庞大(STL + 标准库)
内存管理 手动(malloc/free) 手动(new/delete)+ 智能指针
编译方式 编译成机器码 编译成机器码
典型应用 操作系统、嵌入式 游戏、浏览器、数据库、高频交易

三、C/C++ 和你学过的语言有什么根本不同

你已经会 JavaScript 和 Python 了,它们都是解释型语言(或者更准确地说,是在虚拟机上运行的)。你写好代码,不需要编译,直接交给解释器就跑起来了。代码出错,解释器会给你一行行指出问题,程序就算崩溃也不会搞坏你的电脑。

C/C++ 完全不同。它需要编译

编译是什么

编译就是把人类可读的源代码翻译成机器可以直接执行的二进制指令。这个过程由编译器(如 GCC、Clang、MSVC)完成。

源代码(.c / .cpp 文件)
    ↓ 编译器
目标文件(.o / .obj 文件)
    ↓ 链接器
可执行文件(.exe / 无后缀的二进制文件)

编译器做的不只是翻译,它还会:

  • 检查语法错误:代码写错了,编译器直接告诉你哪一行有问题,不会让程序带着错误运行。
  • 检查类型错误:C/C++ 是静态类型语言。每个变量的类型在编译时就确定了,不能像 Python 那样把一个整数随时改成字符串。这减少了大量运行时才能发现的 bug。
  • 优化代码:编译器会分析你的代码,进行各种优化——去掉没用到的变量、把循环展开、把频繁调用的函数内联。这些优化让你的程序跑得更快。

编译完成后,你拿到的是一个独立的可执行文件。双击它就能直接运行,不需要安装 Python 解释器、不需要 Node.js 运行时、不需要任何额外的东西。这就是为什么你下载的游戏安装包可以直接运行——它们就是用 C++ 编译好的二进制文件。

静态类型 vs 动态类型

在 JavaScript 中,你可以这样写:

// JavaScript(动态类型)
let x = 10;
x = 'hello';  // 完全没问题

在 Python 中同样可以:

# Python(动态类型)
x = 10
x = 'hello'  # 完全没问题

在 C/C++ 中不行:

// C/C++(静态类型)
int x = 10;
x = "hello";  // 编译错误!类型不匹配

每个变量在声明时就必须指定类型,而且这个类型终身不变。这看起来像是限制,但实际上它是一种保护——在你运行程序之前,编译器已经帮你检查了大量潜在的错误。

内存管理:你自己决定一切

JavaScript 和 Python 都有垃圾回收机制。你创建一个对象,用完了不管它,运行时环境会自动在某个时候把这块内存收回去。你几乎不需要想“这个变量占了多少内存?什么时候释放它?”

C/C++ 没有垃圾回收。你申请的内存,你必须自己释放。

这听起来很可怕,事实也确实如此。内存管理是 C/C++ 学习中最陡峭的一道坎。你会遇到:

  • 内存泄漏:申请了内存但忘了释放,程序运行越久占内存越多,最后把系统资源耗尽。
  • 野指针:指向一块已经被释放的内存。读写野指针可能导致程序崩溃,或者更可怕的——不崩溃,但读到了错误的数据。
  • 栈溢出:在栈上分配了太大的数据(比如一个几百万元素的数组),超出了操作系统给每个程序分配的栈空间。

但手动管理内存也是 C/C++ 高性能的根源。你没有垃圾回收器的开销,你精确控制每一块内存的生命周期。在高性能场景(如游戏引擎、音视频编解码)中,这种控制力是任何带垃圾回收的语言都无法提供的。

四、C/C++ 能做什么

你可以用 JavaScript 写网页、用 Python 做数据分析,那 C/C++ 到底用来做什么?

  • 操作系统:Windows 的内核是用 C 写的,Linux 的内核也是 C,macOS 的 XNU 内核主要是 C 和少量 C++。你正在用的操作系统的核心,就是 C 语言写的。
  • 浏览器内核:Chrome 的渲染引擎 Blink 和 JavaScript 引擎 V8,都是用 C++ 写的。你之前写的每一行 JavaScript,最终都是由 C++ 代码来执行的。
  • 数据库:MySQL、PostgreSQL、MongoDB——几乎所有需要高性能的数据存储系统,底层都是 C/C++。
  • 游戏引擎:虚幻引擎(Unreal Engine)是用 C++ 写的,大量 3A 游戏使用它。Unity 的底层也是 C++。C# 只是写游戏逻辑的脚本层,真正干重活的是 C++。
  • 音视频处理:FFmpeg(几乎所有视频播放软件和转码工具的核心)是 C 写的。OBS(直播推流软件)是 C/C++ 写的。
  • 嵌入式系统:你家里的路由器、智能音箱、汽车的行车电脑——这些硬件资源非常有限(可能只有几百 KB 的内存),必须用 C 来写固件。
  • Node.js 和 Python 本身:没错,Node.js 的 V8 引擎是 C++ 写的,Python 的官方解释器 CPython 是 C 写的。你写的 JavaScript 和 Python 代码,最终跑在一个用 C/C++ 写的程序里。

C/C++ 是一种基础设施语言。你可能不直接用它写应用,但你用的几乎所有软件,底层都有它的身影。

五、安装开发环境

C/C++ 没有像 Python 那样自带一个统一的解释器。你需要安装编译器。不同操作系统上推荐的编译器不同。

Windows:安装 MinGW-w64

MinGW-w64 是 GCC 编译器在 Windows 上的移植版。GCC 是 Linux 上最标准的 C/C++ 编译器。

  1. 打开浏览器,搜索 MinGW-w64,进入官方下载页面。
  2. 或者直接访问 https://www.mingw-w64.org/
  3. 下载安装程序,运行。安装时注意选择架构为 x86_64
  4. 安装路径建议用默认的 C:\mingw-w64\
  5. 安装完成后,需要把 bin 文件夹添加到系统环境变量 PATH 中。具体步骤:右键“此电脑” → 属性 → 高级系统设置 → 环境变量 → 在系统变量中找到 Path → 编辑 → 新建 → 填入 C:\mingw-w64\bin(改成你实际安装的路径)。

验证安装:打开终端(Win+R → cmd),输入:

gcc --version

如果出现版本号(如 gcc 13.2.0),说明安装成功。

Mac:安装 Xcode Command Line Tools

打开终端,输入:

xcode-select --install

系统会弹窗询问是否安装,点“安装”。等待几分钟。这会把 Clang 编译器(苹果系统上的标准 C/C++ 编译器)安装到你的 Mac 上。

验证安装:

gcc --version

Mac 上 gcc 实际上指向 Clang,不用在意。只要出现版本号就行。

Linux(Ubuntu/Debian):

sudo apt update
sudo apt install build-essential

这会安装 GCC 编译器以及相关的工具链。验证:gcc --version

六、你的第一段 C 程序

现在我们用 C 写一个最简单的程序。注意后缀:C 程序用 .c,C++ 程序用 .cpp

新建一个文件 hello.c

#include <stdio.h>

int main() {
    printf("你好,世界!\n");
    return 0;
}

打开终端,进入该文件所在目录,输入:

gcc hello.c -o hello

解释

  • gcc:调用 GCC 编译器。
  • hello.c:要编译的源文件。
  • -o hello:指定输出的可执行文件名为 hello(Windows 上会自动加 .exe 后缀)。

编译完成后,当前目录下会生成一个 hello(或 hello.exe)文件。在终端中执行:

# Windows
hello.exe

# Mac / Linux
./hello

终端会输出:

你好,世界!

七、逐行解释这段 C 代码

这段代码只有 5 行,但包含了 C 程序的基本骨架。

#include <stdio.h>

  • #include预处理指令。在编译之前,预处理器会先把 stdio.h 这个文件的内容复制粘贴到这里。
  • stdio.h 是 C 标准库的头文件(header file),包含了输入输出相关的函数声明——比如 printf
  • .h 后缀表示“头文件”,它只包含函数声明,不包含函数实现。真正的实现在编译好的库文件里。
  • 这和 Python 的 import 或 JavaScript 的 require 类似,但机制完全不同——#include 就是字面意义上的“把文件内容复制到这里”。

int main() {

  • main 是 C 程序的入口函数。程序启动时,操作系统会调用 main 函数。每个 C 程序必须有且只有一个 main 函数。
  • int 表示 main 函数返回一个整数。返回给谁?返回给操作系统。0 表示程序正常退出,非 0 表示出错。
  • 花括号 { 表示函数体的开始。

printf("你好,世界!\n");

  • printf 是 C 标准库中最常用的函数之一,用来格式化输出文字到终端。相当于 Python 的 print()、JavaScript 的 console.log()
  • \n 是换行符。C 语言的字符串不会自动换行,需要手动加 \n。不加的话,终端光标会停留在输出文字的末尾。
  • 注意这行末尾的分号。C 语言中,每条语句必须以分号结尾。这和 JavaScript 不同(JS 的分号是可选的),和 Python 不同(Python 不需要分号)。忘记分号是 C 初学者最常见的错误。

return 0;

  • return 结束 main 函数,并把 0 返回给操作系统。0 表示“程序正常结束”。

}

  • 花括号结束,表示 main 函数体结束。

八、C 和 Python/JavaScript 的语法初对比

特性 JavaScript Python C
打印输出 console.log('hello') print('hello') printf("hello\n");
语句结尾 分号可选 不需要 必须加分号
代码块 { } 花括号 缩进 { } 花括号
入口函数 脚本顶部开始执行 脚本顶部开始执行 必须有 main 函数
变量声明 let x = 10; x = 10 int x = 10;(必须指定类型)
类型检查 运行时 运行时 编译时
运行方式 解释执行(浏览器或 Node.js) 解释执行(Python 解释器) 先编译成二进制,再执行

九、编译型的开发流程

习惯了 Python 和 JavaScript 的“写完就跑”,你需要适应 C/C++ 的“写完 → 编译 → 跑”。

1. 写代码 → hello.c
2. 编译   → gcc hello.c -o hello
3. 运行   → ./hello
4. 改代码 → 回到第 1 步

如果你不改代码,不需要重新编译。编译好的 hello 文件可以直接发给别人,不需要对方装任何编译器或运行时。这就是编译型语言的便携性。

当代码越来越多,每次都手动敲 gcc 会很麻烦。后面我们会学到 Makefile——一个让编译过程自动化的工具。

十、本篇动手练习

练习 1:安装并验证环境

按本文第五节的指引,在你的操作系统上安装编译器。用 gcc --version 验证安装成功。

练习 2:编译并运行你的第一个程序

手敲第六节的 hello.c 代码,编译并运行。不要复制粘贴——手敲能帮你记住分号、括号、花括号的位置。

练习 3:制造编译错误

故意做以下修改,看编译器报什么错:

  • 删掉一个分号。
  • printf 写成 print
  • 删掉 #include <stdio.h> 这一行。

读编译器的报错信息。不要害怕它们——编译器不是在骂你,是在帮你找问题。学会读编译错误是 C/C++ 编程的基本功。

练习 4:修改程序

printf 中再加一行输出,打印你的名字。例如:

printf("你好,世界!\n");
printf("我叫张三。\n");

重新编译并运行。

十一、本篇小结

这一篇你正式进入了 C/C++ 的世界:

  • C 和 C++ 的关系:C++ 是 C 的超集,加入了面向对象、模板等特性。C 面向过程,C++ 多范式。实际应用中两者经常混用。
  • C/C++ 和你之前学的语言的根本区别:编译型 vs 解释型、静态类型 vs 动态类型、手动内存管理 vs 垃圾回收。
  • 编译是什么:把源代码翻译成机器可直接执行的二进制文件。编译过程包含语法检查、类型检查、代码优化。
  • C/C++ 的应用领域:操作系统、浏览器内核、数据库、游戏引擎、嵌入式——都是对性能和硬件控制要求最高的领域。
  • 开发环境搭建:Windows 安装 MinGW-w64,Mac 安装 Xcode Command Line Tools,Linux 安装 build-essential。
  • 第一个 C 程序#include 引入头文件、main 函数是入口、printf 输出文字、return 0 返回给操作系统、每条语句以分号结尾。

下一篇,我们正式开始学 C 语言的语法基础——变量声明、基本数据类型(int、float、char)、运算符、输入输出。你会发现,C 的变量声明方式和 JavaScript/Python 完全不一样,但这种“繁琐”背后是对性能和内存的精确控制。

下一篇预告

下一篇——《C 语言语法基础:变量、数据类型、输入输出》:变量声明必须指定类型、基本数据类型和它们占用的内存大小、格式化输入输出 printfscanf、运算符和表达式。同时对比 Python/JavaScript 中对应的概念,降低学习曲线。

C/C++ 零基础入门,每周更新。

© 版权声明
THE END
喜欢就支持一下吧
点赞9 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容