C | C++ | |
---|---|---|
问世时间、创始公司 | 1972,Bell Laboratory | 1979,Bell Laboratory |
OOP 能力 | 不支持 | 强大,但复杂 |
类型系统 | 强类型 | 强类型 |
运行模式 | 原生编译 | 原生编译 |
跨平台能力 | 一般 | 一般 |
性能 | 极高 | 极高 |
关键词 | 高性能、底层 | 高性能、面向对象 |
Hello World 程序:
// C
#include <stdio.h>
int main() {printf("Hello, world!\n");return 0;
}
// Cpp
#include <iostream>
int main() {std::cout << "Hello, world!" << std::endl;return 0;
}
简介
推荐的书:《C Primer Plus》《C++ Primer Plus》
在过去 40 多年里,C 语言已成为最重要、最流行的编程语言之一。
虽然这些年来 C++ 和 JAVA 非常流行,但是 C 语言仍是软件业中的核心技能。在最想具备的技能中,C 语言通常位居前十。特别是,C 语言已成为嵌入式系统编程的流行语言。也就是说,越来越多的汽车、照相机、DVD 播放机和其他现代化设备的微处理器都用 C 语言进行编程。除此之外,C 语言还从长期被FORTRAN 独占的科学编程领域分得一杯羹。最终,作为开发操作系统的卓越语言,C 在 Linux 开发中扮演着极其重要的角色。因此,在进入 21 世纪的第 2 个10 年中,C 语言仍然保持着强劲的势头。
摘自:《C Primer Plus》,粗体是笔者加的
欢迎进入 C++ 世界!这是一种令人兴奋的语言,它在 C 语言的基础上添加了对面向对象编程和泛型编程的支持,在 20 世纪 90 年代便是最重要的编程语言之一,并在 21 世纪仍保持强劲势头。 C++ 继承了 C 语言高效、简洁、快速和可移植性的传统。 C++ 面向对象的特性带来了全新的编程方法,这种方法是为应付复杂程度不断提高的现代编程任务而设计的。 C++ 的模板特性提供了另一种全新的编程方法——泛型编程。这三件法宝既是福也是祸,一方面让 C++ 语言功能强大,另一方面则意味着有更多的东西需要学习。
摘自:《C++ Primer Plus》,粗体是笔者加的
C/C++ 都有内存占用小、性能好、接近底层的特征,而且生态相对成熟,几乎可以完成所有的编程任务。
C/C++ 学习曲线开始较平缓(尽管深入后变得陡峭),使其成为初学者的首选语言之一。
典型应用
- 系统编程:编写操作系统(OS)、设备驱动、芯片固件、系统管理软件、编译器和解释器、数据库系统(SQL)等。
- 高性能开发:浏览器引擎、游戏引擎、图像渲染、物理模拟、金融系统等。
- 嵌入式开发 & 物联网:单片机等微处理器上的程序。
- 底层开发:需要直接与硬件、系统 API 交互的场景。
另外一说,C/C++ 也是恶意程序偏爱的语言。(所以 C/C++ 程序有时容易被杀毒软件索敌。。。)
高性能
C/C++ 程序的性能上限很高,原因主要有:
- C/C++ 原生编译运行,相比托管语言(如 Java、C#、Python 等),没有托管环境的 “中间层”,操作更快。
- C/C++ 提供了 “强大而灵活” 的功能,恰当利用它们可以大幅提高程序性能。例如:位操作、指针等。
零开销抽象
C++ 的零开销抽象(Zero-overhead Abstraction)是C++设计的重要原则之一:
- 不为不使用的功能付出代价(You don't pay for what you don't use)。
- 你使用的东西,你不可能用更低的代价手工实现(What you do use is just as efficient as what you could have written by hand)。
这使得 C++ 的性能与 C 接近,还可以 “免费” 享受抽象的便利。
内存开销小,手动管理
相比托管语言,C/C++ 的内存开销十分优秀。这是因为托管语言的内存需要垃圾收集器(GC)来释放,而 C/C++ 的内存由程序员手动管理(包括内存的申请和释放)。一般来说,程序员比 GC 更知道 “内存该何时释放”,因而 C/C++ 的内存开销几乎是最小的。
内存模型简介
C/C++ 是需要手动管理内存的语言。作为这类语言的代表,这里简单介绍一下 C/C++ 的内存模型。
C/C++ 有两种内存:栈内存、堆内存。在函数体中直接声明的变量,其存在栈内存中。栈内存由系统自动分配,在栈内储存的变量在编译时确定(自由度比较低)。栈内存的一个例子:
// C
int main() {int a = 0;char str[] = "Hello, world!";return 0;
}
a
和 str[]
都在栈内存中。栈内存中的变量会在其声明周期结束后自动释放。在本例中,main()
退出时就会释放 a
和 str[]
。栈内存是连续的,在内存地址上,a
和 str[]
是紧邻的。
堆内存需要手动分配和释放,且申请速度较慢(因为需要 System Operation)。以下是例子:
// C
#include <stdlib.h>
int* func() {int* p = malloc(sizeof(int));return p;
}
int main() {int* q = func();free(q);return 0;
}
在本例中第 4 行,我们用 malloc()
在堆上申请一块内存,并用一个指针 int *p
来接收它。注意尽管我们申请的内存在堆上,但是指向这块内存的指针 p
是存储在栈内存中的。第 6 行,p
的声明周期结束,其被释放,但是其指向的堆内存并没有释放。在第 9 行,我们用 free
手动释放这块内存。
C++ 用,可以用 new
和 delete
来申请、释放内存,更方便一些。
底层能力
C/C++ 的底层能力是显著优势,具体来说:
-
C/C++ 提供直接的内存操作,也就是程序员可以很自由地操作指针。具体请见上一节。
-
一些系统级 API 是以 C/C++ 提供的。例如,在 Windows 系统上,我们直接通过 Windows API 写入文件(这允许我们进行更高级的文件操作):
// C #include <windows.h> int main() {HANDLE file = CreateFileA("test.txt", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);const char* data = "Hello, Windows API!";DWORD bytesWritten;WriteFile(file, data, strlen(data), &bytesWritten, NULL);CloseHandle(file);return 0; }
-
直接与硬件操作。例如,直接控制串口通信(如 USB 通信)。具体来说比较复杂,这里不举例了。
-
硬件特定优化:例如 SIMD、缓存优化等。
还有更多对内存、CPU 等的精细操作可以通过 C/C++ 完成,这里也不举例了。
弊端
C/C++ 不是没有缺陷的,下面介绍它们的弊端。
指针与内存管理
从前面的内容不难看出,堆内存需要程序员手动释放,如果程序员忘了释放,将导致 “内存泄漏” 的灾难。C++ 提供了智能指针(如 std::shared_ptr
)来帮助程序员管理内存,但总体来说内存管理仍是 C/C++ 程序员需要面对的挑战。除此之外,还有可能遇到空指针、野指针等挑战。
异常机制(C++)
C++ 的异常机制几乎是 “半残” 的。要保证 C++ 程序的异常安全通常比较难,而且不推荐使用。这主要因为:
-
C++ 抛出的异常可以是任何类型,甚至是
void
。这使得捕获所有异常比较困难。 -
C++ 不要求函数声明它抛出什么异常,这样就不容易知道需要处理哪些异常。
-
C++ 标准库抛出异常的行为比较混乱。例如:
// Cpp #include <vector> int main() {std::vector<int> v;v.at(10); // 抛出 std::out_of_rangev[10]; // 未定义行为,不保证抛出return 0; }
C++ 中不推荐使用异常机制,这还有一个原因:写异常处理代码可能导致额外的开销,这违背了 C++ “零成本抽象” 的理念。
标准库有限 & 生态碎片
如果仅使用 C/C++ 的标准库,要开发现代的应用程序有一定难度,因为如网络编程、一些 IO 功能(比如 JSON 解析),标准库没有支持。这其实和 C/C++ 标准库的定位有关。
标准库功能的范围有限(基本上只有核心的算法),因而往往需要使用很多第三方库来补充和拓展,这就使得快速上手开发变得比较困难。当然,这也催生了如 Boost,Qt 等解决方案,它们集合了大量通用功能(基本上是 “大杂烩”)。(后面会介绍)
这些第三方库百家争鸣,有时一个功能有好几个开源库实现,但支持情况、维护频率又有所不同,各个库之间的协作效果有时不尽人意……这就构成了 “生态碎片” 的问题。
晦涩(有时)
这其实取决于程序员如何写 C/C++。由于 C/C++ 的 “强大和灵活”,程序员可以写出像这样的代码(OIer 可能比较眼熟):
// C
#include <stdio.h>
#include <ctype.h>
int read() {char c = getchar(); int x = 0;while (!isdigit(c)) c = getchar();while (isdigit(c))x = (x << 3) + (x << 1) + (ch ^ 48), c = getchar();return x;
}
第 7 行看着是不是一头雾水? x = (x << 3) + (x << 1)
实际上与 x *= 10
等效,ch ^ 48
与 ch - '0'
等效。我们采取晦涩的写法,一定程度上可以增强性能,但是牺牲了可读性。
困境
C/C++ 如此强大,但是要用 C/C++ 快速开发一个现代应用程序,却充满挑战:
- 技术选型:不得不使用第三方库,难以回避生态碎片的问题。
- GUI:要用 C/C++ 开发出现代的 GUI 程序比较困难。
- 编译问题:C/C++ 多源文件编译比较缓慢(相比 Java、C# 等),没有真正的模块系统。这主要是编译时的预处理(比如处理
#include
)导致的。虽然有一些缓解措施(比如 “预编译头”),但仍是核心痛点之一。 - 开发体验:比如写
::
不如.
方便,方法的声明和定义要分离,等等。
如果你想快速开发一个现代应用程序,笔者推荐 C#。
生态
C/C++ 的生态很发达,这里只举一些代表性的例子。
Boost
Boost 是一个广泛使用的 C++ 库集合,它提供了许多功能,覆盖了多个领域,如算法、容器、函数式编程、泛型编程、模板元编程、并发编程等。Boost 库通常被认为是“准标准”库,因为许多 Boost 库后来被纳入 C++ 标准。例如,C++11 及以后的标准中引入了智能指针(shared_ptr, weak_ptr)、正则表达式、线程库等,这些都在 Boost 中先出现。
由 DeepSeek 总结,供参考
Boost 尽管功能全面,但是历史悠久,技术债逐渐累积,如今也不是太好用。Boost 的地位或许会逐渐下降,Boost 的一些组件也逐渐有了更优的替代。
Qt
Qt 是一个跨平台的 C++ 应用程序开发框架。它远不止一个 GUI 库,而是一个全面的工具集,用于创建高性能、现代化的桌面、嵌入式和移动应用。
Qt 的商业模式
- 开源版本(Qt for Open Source):使用 GPL/LGPL 许可证。如果你的项目也是开源的,可以免费使用。
- 商业版本:提供专业的技术支持、更宽松的许可证(允许闭源开发)和额外的工具模块。需要付费购买。
谁在使用 Qt?
Qt 被广泛应用于各个领域:
- 汽车:宝马、奥迪、特斯拉等品牌的车载信息娱乐系统。
- 工业自动化:工业控制软件、医疗设备界面。
- 嵌入式设备:智能家居中控、路由器管理界面、机顶盒。
- 知名软件:Autodesk Maya, Adobe Photoshop Elements, VirtualBox, WPS Office, VLC 媒体播放器等。
由 DeepSeek 总结,供参考
Qt 的主要特点是:跨平台、全面、GUI。不少常见的应用也是用 Qt 编写的。因为 Qt 的商业模式,其在闭源软件中的使用不多(听说授权费很高)。
笔者体验过一点 Qt,感觉工具链不是很成熟,而且 Qt 做出来的 UI 颜值一般。笔者个人认为,Qt 有些古老了,其 “信号与槽” 的框架有更优秀、更简洁的替代(比如 XAML 的绑定语法)。而且 SDK 和 Runtime 都的体积都挺大的。如果你用 Qt 做一些小程序,那么发布包会显得很大。
Qt 给笔者一种 “笨拙” 的感觉。
可以看看:Qt血的教训/细数Qt开发的各种坑/又爱又恨/欢迎围观留言评论 - 飞扬青云 - 博客园。
Visual C++
核心组成部分
Visual C++ 主要包含以下几个关键部件:
- VC++ 编译器 (cl.exe)
- 负责将 C/C++ 源代码编译成目标代码和可执行文件。它以其高性能和深度优化而闻名,特别是对 Windows 平台的优化。
- Visual Studio IDE
- 提供强大的代码编辑器、调试器、项目管理器、UI 设计器等,极大地提高了 C++ 的开发效率。
- Microsoft C++ 标准库
- 包括 C 运行时库 和 C++ 标准库的实现。
- Windows API 和 SDK
- 提供访问 Windows 操作系统核心功能的接口,是开发原生 Windows 应用程序的基础。
- MFC 和 ATL
- MFC:微软基础类库,一个用于快速构建传统 Windows 桌面应用程序 UI 的 C++ 类库,在早期非常流行。
- ATL:活动模板库,用于轻量级、高效的 COM 组件开发。
由 DeepSeek 总结,供参考
Visual 是微软推出的一套 SDK,在 Windows 平台上挺重要的。其工具链成熟,开发还算流畅。我认为有以下不足:
- Windows API:这是很低级的 API,如果你想用它开发现代程序(比如写 GUI),那简直是折磨。(不要这么做。)
- MFC:提供比 Windows API 高级点的封装,但是也不是很理想。MFC 可以让你 “拖拖拽拽” 就整出一个 GUI 程序。非常非常简单的程序还勉强可以用 MFC;如果 UI 或者程序需求比较复杂(多页、多窗口),不建议使用 MFC,这是挺古老的技术了。
其他
放在 “其他” 不代表它们就不重要!这只是因为笔者对他们了解不多。
- OpenCV:开源的计算机视觉库。
- POCO:一套功能强大的跨平台开源 C++ 库。
- NVIDIA CUDA:使用 NVIDIA 图形卡强大的并行计算功能,可以用于机器学习、图像渲染等场景。
- Unreal Engine:知名的游戏引擎。
Ending
以上就是 C/C++ 的介绍了。C/C++ 是很复杂的语言,无论是语法特性还是生态现状都不简单。笔者能力有限,只能介绍自己比较熟悉的部分。笔者曾有多年的 C/C++ 经验,在这里也是付出过心血踩过坑,对 C/C++ 真是又爱又恨。