This commit is contained in:
许大仙 2024-08-09 14:47:44 +08:00
parent 6cdcfc7c65
commit 5aed68cf32
31 changed files with 635 additions and 630 deletions

View File

@ -6,6 +6,7 @@ export const sidebar: DefaultTheme.Sidebar = {
text: 'C 语言基础',
collapsed: true,
items: [
{ text: '编程基础', link: `/notes/01_c-basic/00_${commonDirectoryName}/` },
{ text: 'C 语言入门', link: `/notes/01_c-basic/01_${commonDirectoryName}/` },
{ text: '变量和进制', link: `/notes/01_c-basic/02_${commonDirectoryName}/` },
{ text: '数据类型和运算符', link: `/notes/01_c-basic/03_${commonDirectoryName}/` },

Binary file not shown.

After

Width:  |  Height:  |  Size: 281 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 785 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 401 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 171 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 111 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 249 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 283 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,552 @@
# 第一章:计算机组成原理
## 1.1 计算机系统
* 计算机Computer俗称`"电脑"`,是一种能够接收和存储信息,并按照存储在其内部的程序对海量的数据进行自动、高速的处理,然后将处理结果输出的现代化智能电子设备。
* 计算机有很多形式,如:台式电脑、笔记本电脑、智能手机、平板电脑等,还有生产环境中提供重要业务支撑的各种服务器。
![](./assets/1.jpg)
* 一个完整的`计算机系统``硬件Hardware系统``软件Software系统`两大部分组成,即:
![](./assets/2.png)
## 1.2 冯·诺依曼体系结构
* `冯·诺依曼`是一位多才多艺的科学家,他在数学、物理学、计算机科学、经济学等领域都有杰出的贡献。
![](./assets/3.jpg)
* `冯·诺依曼`的主要成就:
- 在计算机科学领域的最著名贡献是提出了`冯·诺依曼`体系结构1946 年),这是`现代计算机设计的基础`
- 促进了计算机的可编程性和通用性,使得计算机能够执行各种复杂的任务。
- 对核武器设计、自动化控制系统、人工智能等领域的发展产生了重要影响。
- ……
> [!IMPORTANT]
>
> `冯·诺依曼体系结构`是现代计算机(量子计算机除外)设计的`基础`
* `冯·诺依曼`体系结构的理论要点如下:
- ① **存储程序**`程序指令``数据`都存储在计算机的内存中,这使得程序可以在运行时修改。
- ② **二进制逻辑**:所有`数据``指令`都以`二进制`形式表示。
- ③ **顺序执行**:指令按照它们在内存中的顺序执行,但可以有条件地改变执行顺序。
- ④ **五大部件**:计算机由`运算器``控制器``存储器``输入设备``输出设备`组成。
- ⑤ **指令结构**:指令由操作码和地址码组成,操作码指示要执行的操作,地址码指示操作数的位置。
- ⑥ **中心化控制**计算机的控制单元CPU负责解释和执行指令控制数据流。
![](./assets/4.png)
> [!NOTE]
>
> 上述的组件协同工作,构成了一个完整的计算机系统:
>
> * **运算器**和**控制器**通常被集成在一起组成中央处理器CPU负责数据处理和指令执行。
> * **存储器**保存数据和程序,是计算机运作的基础。
> * **输入设备**和**输出设备**负责与外界的交互,确保用户能够输入信息并接收计算机的处理结果。
## 1.3 各种硬件处理速度和性能优化
* 计算机的性能短板:如果 CPU 有每秒处理 1000 个服务请求的能力,各种总线的负载能力能达到 500 个, 但网卡只能接受 200个请求而硬盘只能负担 150 个的话,那这台服务器得处理能力只能是 150 个请求/ 秒,有 85% 的处理器计算能力浪费了,在计算机系统当中,`硬盘`的读写速率已经成为影响系统性能进一 步提高的瓶颈。
![img](./assets/5.jpg)
* 计算机的各个设备部件的延迟从高到低的排列依次是机械硬盘HDD、固态硬盘SSD、内存、CPU 。
![img](./assets/6.png)
* 从上图中我们可以知道CPU 是最快的,一个时钟周期是 0.3 ns ,内存访问需要 120 ns ,固态硬盘访问需要 50-150 us传统的硬盘访问需要 1-10 ms而网络访问是最慢需要 40 ms 以上。
* 时间的单位换算如下:
```txt
1 秒 = 1000 毫秒,即 1 s = 1000 ms。
1 毫秒 = 1000 微妙,即 1 ms = 1000 us 。
1 微妙 = 1000 纳秒,即 1 us = 1000 ns。
```
* 按照上图,将计算机世界的时间和人类世界的时间进行对比,即:
```txt
如果 CPU 的时钟周期按照 1 秒计算,
那么,内存访问就需要 6 分钟;
那么,固态硬盘就需要 2-6 天;
那么,传统硬盘就需要 1-12 个月;
那么,网络访问就需要 4 年以上。
```
* 所以,对于 CPU 来说,这个世界真的是太慢了!!!
* 其实,中国古代中的文人,通常以`蜉蝣`来表示时间的短暂(和其他生物的寿命比),也是类似的道理,即:
```txt
鹤寿千岁,以极其游,蜉蝣朝生而暮死,尽其乐,盖其旦暮为期,远不过三日尔。
--- 出自 西汉淮南王刘安《淮南子》
```
```txt
寄蜉蝣于天地,渺沧海之一粟。 哀吾生之须臾,羡长江之无穷。
挟飞仙以遨游,抱明月而长终。 知不可乎骤得,托遗响于悲风。
--- 出自 苏轼《赤壁赋》
```
>[!NOTE]
>
>对于`蜉蝣`来说,从早到晚就是一生;而对于我们`人类`而言,却仅仅只是一天。
* 存储器的层次结构CPU 中也有存储器,即:寄存器、高速缓存 L1、L2 和 L3如下所示
![img](./assets/7.png)
>[!NOTE]
>
>上图以层次化的方式,展示了价格信息,揭示了一个真理,即:鱼和熊掌不可兼得。
>
>- ① 存储器越往上速度越快,但是价格越来越贵, 越往下速度越慢,但是价格越来越便宜。
>- ② 正是由于计算机各个部件的速度不同,容量不同,价格不同,导致了计算机系统/编程中的各种问题以及相应的解决方案。
>
>总结CPU 都是直接和内存打交道的CPU 会直接从内存中读取数据,待数据处理完毕之后,会将结果再次写入到内存中;如果需要将数据持久化(永久)保存(内存是易失性存储器,内存中的数据是以电荷形式存储在存储单元中的。当计算机关闭或断电时,这些电荷很快消散,导致存储在内存中的数据丢失),那么就会内存中的数据再刷新到磁盘或硬盘上,即:落盘。
## 1.4 计算机软件
### 1.4.1 操作系统的来源
* 在上古时期,硬件资源不够丰富,计算机设计的也非常简陋。那个时候,很多应用程序都是直接跑在硬件上的,即:一个计算机只能跑一个应用程序。
![](./assets/8.png)
* 随着技术的发展,硬件越来越丰富,功能也越来越强大,性能也越来越好。这种情况下,如果一台计算机只能跑一个程序,实在是太浪费了。而且,底层硬件不断丰富,应用程序需要对接的硬件也将越来越多,如果每个应用程序都这么干,不显示工作很重复吗?于是,操作系统应运而生了。
![](./assets/9.png)
- 操作系统的功能:
- 硬件驱动。
- 进程管理。
- 内存管理。
- 网络管理。
- 安全管理。
- 文件管理。
* 那么,操作系统的作用,就是这样的,即:
* 对下,管理计算机的硬件资源。
* 对上,提供使用计算机资源的操作方式,有:
* `系统调用`:是一套已经写好的代码接口,应用程序通过调用这些接口来请求操作系统执行特定的硬件操作。它们直接与硬件交互,提供底层功能支持,如:文件操作、进程管理、内存管理等。`开发者`通过系统调用可以实现对底层资源的直接控制,确保程序能够高效、安全地运行。
* `终端命令`:是一种文本命令接口,通过命令行输入各种指令来控制操作系统和软件的行为。终端命令可以执行文件操作、系统配置、网络管理等各种任务。主要针对`开发人员``高级用户`,他们通过命令行可以快速、精确地完成各种操作,提高工作效率。
* `图形用户界面`GUI是通过图形元素窗口、图标、按钮等与用户进行交互的界面。供直观、易用的操作方式使用户能够通过鼠标点击、拖拽等简单操作完成复杂任务。主要面向`普通用户`,降低了计算机操作的门槛,提高了用户体验和工作效率。
![](./assets/10.png)
### 1.4.2 用户态和内核态
* 在现代操作系统中,`用户态User Mode``内核态Kernel Mode`是两种不同的执行模式,它们对系统资源的访问权限有着本质的区别。这种区分是为了提供一个稳定和安全的运行环境,防止用户程序直接操作硬件设备和关键的系统资源,从而可能引起系统的不稳定或安全问题。
![](./assets/11.png)
- 核态Kernel Mode VS 用户态User Mode
| 类型 | 内核态Kernel Mode | 用户态User Mode |
| :----- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| 权限 | 内核态是操作系统代码运行的模式,拥有访问系统全部资源和执行硬件操作的`最高权限`。在这种模式下,操作系统的核心部分可以直接访问内存、硬件设备控制、管理文件系统和网络通信等。 | 用户态是普通应用程序运行的模式,具有`较低`的系统资源访问权限。在用户态,程序不能直接执行硬件操作,必须通过操作系统提供的接口(即系统调用)来请求服务。 |
| 安全性 | 由于内核态具有如此高的权限,因此只有可信的、经过严格审查的操作系统核心组件才被允许在此模式下运行。这样可以保护系统不被恶意软件破坏。 | 用户态为系统提供了一层保护,确保用户程序不能直接访问关键的系统资源,防止系统崩溃和数据泄露。 |
| 功能 | 内核态提供了`系统调用`的接口,允许用户态程序安全地请求使用操作系统提供的服务,比如:文件操作、网络通信、内存管理等。 | 用户态保证了操作系统的稳定性和安全性,同时也使得多个程序可以在相互隔离的环境中同时运行,避免相互干扰。 |
> [!NOTE]
>
> - ① 操作系统通过用户态和内核态的分离,实现了对系统资源的保护和控制。
> - ② 当用户程序需要进行文件读写、网络通信或其他需要操作系统介入的操作时会发生从用户态到内核态的切换。这通过系统调用System Call实现系统调用是用户程序与操作系统内核通信的桥梁。
> - ③ 执行完毕后,系统从内核态返回用户态,继续执行用户程序。
> - ④ 用户态和内核态的这种分离设计是现代操作系统中实现安全、稳定运行的关键机制之一。
* 示例:
```java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class Demo {
public static void writeFile(String filePath, String content) {
Path path = Paths.get(filePath);
try {
Files.write(path, content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
int a = 10; // 用户态
int b = 20; // 用户态
int c = a + b; // 用户态
string filePath = "c:/demo.txt"; // 用户态
string txt = a + b + c; // 用户态
writeFile(filePath, a); // 从用户态切换到内核态完成文件写入
System.out.println(a); // 从内核态切换回用户态
System.out.println(b); // 用户态
System.out.println(c); // 用户态
}
}
```
### 1.4.3 ISA、ABI 和 API
- ISA 、ABI 和 API 的参考模型如下:
![](./assets/12.jpg)
* 在底层,硬件模型以指令集架构 ISA 表示该架构定义了处理器、寄存器、存储器和中断管理的指令集。ISA 是硬件和软件之间的接口,对于操作系统 OS 开发人员 System ISA 和直接管理底层硬件的应用程序 User ISA 的开发人员来说非常重要。
> [!NOTE]
>
> - ① ISA 是计算机体系结构中定义的一组指令它规定了处理器能够执行的操作。ISA 包括指令的编码、寄存器的使用、内存访问模式等。不同的处理器可能有不同的 ISA例如x86、ARM、MIPS 等。
> - ② 在设计一个新的操作系统时,开发者需要确保操作系统能够支持特定的 ISA ,以便在特定的硬件上运行。例如:如果操作系统旨在运行在 ARM 架构的处理器上,那么它必须能够理解和执行 ARM ISA 定义的指令集。
- 应用程序二进制接口 ABI`操作系统层`与由操作系统管理的`应用程序``库`分开。ABI 涵盖了低级数据类型、对齐方式和调用约定等详细信息,并定义了可执行程序的格式。系统调用在此级别定义。此接口允许应用程序和库在实现相同 ABI 的操作系统之间移植。
> [!NOTE]
>
> - ① ABI 是指在二进制级别上应用程序与操作系统、库或应用程序的不同部分之间的接口。它定义了数据类型的大小、布局、对齐方式以及函数调用的约定如参数如何传递、返回值如何处理等。ABI 确保了编译后的二进制文件能够在特定的操作系统和硬件平台上正确地运行。
> - ② 在 windows 上的应用程序的运行格式是:`PE`portable executable格式、`.dll` dynamic link library格式和 `.lib` 格式;而在 Linux 上的应用程序的运行格式是:`ELF`executable and linking format格式、`.so` shared object格式和 `.a` 格式。
> - ③ 在 Linux 中可以通过 `file /bin/ls` 命令查看指定可执行应用程序的 ABI 格式;从而也可以论证,在 Windows 上可以运行的程序,在 Linux 上运行不了。
> - ④ 当开发者在 Linux 系统上编写 C 语言程序并使用特定的编译器GCC编译时编译器会遵循 Linux 平台的 ABI 规范来生成二进制文件。这样,生成的可执行文件就可以在任何遵循相同 ABI 规范的 Linux 系统上运行。
> - ⑤ 如果一个应用程序需要跨平台(操作系统)运行,就需要使用`一套代码,多平台编译`的方式(针对 C 或 C++ 等相同的源代码在不同平台操作系统上使用特定平台的编译器GCC来分别编译成符合自己平台的 ABI 规范的二进制文件。
- 最高级别的抽象由应用程序编程接口 API 表示,它将`应用程序`连接到`库``底层操作系统`
> [!NOTE]
>
> - ① API 是一组预定义的函数、协议和工具用于构建软件和应用程序。API 允许不同的软件系统相互交互它定义了软件组件之间如何相互通信。API 可以是库、框架、协议或服务。
> - ② 在 Web 开发中,开发者可能会使用 JavaScript 的 Fetch API 来与服务器进行通信,获取数据或提交表单。这个 API 提供了一种标准化的方式来发送 HTTP 请求和处理响应,而不需要开发者关心底层的网络协议细节。
### 1.4.4 系统调用System Call和函数库Library Call
* 在现代操作系统中,应用程序都不能直接作用于硬件,而是运行在操作系统之上。
![](./assets/13.png)
- 并且,在上文的图示中,我们也会看到`系统调用System Call``函数库Library Call`的身影,如下:
![](./assets/14.png)
![](./assets/15.png)
* 其实,`系统调用System Call``函数库Library Call`的区别如下:
| 类型 | 系统调用System Call | 函数库Library Call |
| :------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| 定义 | 系统调用是操作系统提供给程序员的一组接口,这些接口允许用户空间的程序请求操作系统内核提供的服务,比如文件操作、进程控制、通信和内存管理等。 | 函数库调用是指使用高级语言编写的一组预先编译好的函数,这些函数实现了一些常用的功能,比如:字符串处理、数学计算等。程序员可以在自己的程序中直接调用这些函数,而无需重新实现它们。 |
| 权限 | 执行系统调用时,会从用户态切换到内核态。这是因为系统调用涉及到访问受保护的系统资源,这些操作必须由操作系统控制以确保系统的稳定性和安全性。 | 函数库调用通常在用户态执行,不涉及到用户态与内核态之间的切换。它们直接使用操作系统通过系统调用提供的服务,或者完全在用户空间内完成计算,不需要操作系统介入。 |
| 性能开销 | 由于涉及到用户态与内核态之间的切换,系统调用的执行成本相对较高。因此,频繁的系统调用可能会影响程序的性能。 | 相对于系统调用,函数库调用的性能开销较小。因为它们通常不涉及到模式切换,且执行的操作多在用户空间完成。 |
| 示例 | open()read()write()fork()exec() 等 UNIX/Linux 系统调用。 | C 标准库中的 printf() 等函数;数学库中的 sin()cos() 等函数。 |
> [!NOTE]
>
> - ① **执行层级**:系统调用直接与操作系统内核交互,执行更底层的操作;而函数库调用运行在用户空间,通常使用系统调用来实现其功能。
> - ② **性能开销**:系统调用由于涉及到用户态与内核态的切换,性能开销相对较大;函数库调用则因为主要在用户态执行,性能开销较小。
> - ③ **使用目的**:系统调用提供了访问操作系统资源和服务的能力;函数库调用则提供了方便、高效执行常见任务的手段。
# 第二章:初识计算机语言
## 2.1 计算机语言是什么?
* `人类语言`是人和人之间用于沟通的一种方式,例如:中国人和中国人之间使用普通话沟通,而中国人和美国人交流,则可以使用英语。
> [!NOTE]
>
> * ① 中文有自己的`固定格式``固定词汇`(即:`语法规则`),英文也是自己的`固定格式``固定词汇`(即:`语法规则`);同样的道理,法语、韩国等各种`人类语言`都有自己的`固定格式``固定词汇`(即:`语法规则`)。
> * ② 在和别的国家的人进行交流的时候,我们必须正确的表达,对方才会理解我们;否则,如果不熟悉对方国家的语言的语法规则,乱用语法规则,可能会贻笑大方,如:中文中的`望其项背`原指看见对方的背影,形容差距不大,能赶上;但是,很多人却认为这是形容遥不可及或难以企及的目标。
> * ③ 就算和本国家的人进行交流的时候,我们也必须正确的表达,对方才会理解我们;否则,如果乱用语法规则,可能也会让对方感觉奇怪,听不懂我们的意思,如:`借我 5000 RMB 买 iphone` 或者 `5000 RMB 我买 iphone 借`
* `计算机编程语言`是人和计算机交流的方式。人们可以使用`编程语言`对计算机下达`命令(指令)`,让计算机完成人们需要的功能。
> [!NOTE]
>
> * ① 计算机语言也有自己`固定格式``固定词汇`(即:`语法规则`),我们必须学习其语法规则,才能控制计算机,让计算机完成我们所需要的功能。
> * ② 计算机语言有很多种C、C++、Java、Go、JavaScript、Python、Scala 等。
## 2.2 为什么要学习计算机语言?
* 编程语言到底是什么?编程语言就是由文字和符号组成的,如:
```c
#include <stdio.h> // 这是编译预处理指令
int main() { // 定义主函数
printf("你好,世界!!!"); // 输出所指定的一行信息
return 0; // 函数执行完毕时返回函数值0
}
```
* 编程语言就是用于控制计算机,让其完成我们需要的功能。而我们学习编程语言,其实就是学习这些文字和符号编写的规则。
* 因为 CPU 只能识别二进制的指令,而我们`编写`的程序叫做`源代码`,是人类能看懂;但是,计算机却不能识别。那么,我们就需要让计算机能识别我们编写的源程序,就需要将我们编写的源代码交给编译器程序,其会帮助我们将所编写的源代码转换为计算机能够识别的二进制指令。
> [!NOTE]
>
> 编译器就是运行在操作系统之上的程序,其作用就是用来将程序员编写的源代码转换为计算机能够识别的二进制指令。
* 如果我们用 Java 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Java 语言的编译器将 Java 程序编译为计算机能够识别的二进制指令。
* 如果我们用 Python 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Python 语言的编译器将 Python 程序编译为计算机能够识别的二进制指令。
* ……
* 总而言之,无论我们学习任何一门编程语言,想要将程序运行起来,都必须做如下的两件事情:
* ① 学习该语言的文字和符号编写的规则,即:`语法规则`
* ② 需要在操作系统上安装对应编程语言的`编译器`程序,将源程序编译为计算机能够识别的二进制指令。
## 2.3 计算机语言简史
### 2.3.1 机器语言(相当于人类的石器时代)
* 1946 年 2 月 14 日,世界上第一台计算机 `ENIAC` 诞生,使用的是最原始的`穿透卡片`
![](./assets/16.png)
* 这种卡片使用的是用`二进制代码`表示的语言,和人类语言差别极大,这种语言就称为`机器语言`,如:
```txt
0000,0000,000000010000 代表 LOAD A, 16
0000,0001,000000000001 代表 LOAD B, 1
0001,0001,000000010000 代表 STORE B, 16
```
* 这种语言本质上是计算机能识别的`唯一语言`,人类很难理解;换言之,当时的程序员 99.9% 都是异类!!!
> [!IMPORTANT]
>
> 不同类型CPU 架构x86_64、arm 等的处理器有不同的机器语言指令集指令集架构ISA决定了机器语言的具体形式换言之机器语言与特定硬件架构紧密相关机器语言程序几乎没有可移植性。
### 2.3.2 汇编语言(相当于人类的青铜&铁器时代)
* `汇编语言`使用`助记符`MOV、ADD、SUB代替二进制操作码使程序更易于人类编写和理解因此`汇编语言`也被称为`符号语言`
![](./assets/17.png)
* 汇编语言的`优点`是能编写`高效率`的程序;但是,`缺点`和机器语言没什么不同,汇编语言同样`依赖于具体的计算机架构(面向机器)`,程序不具备跨平台的可移植性。
> [!NOTE]
>
> 汇编语言,目前仍然应用于工业电子编程领域、软件的加密解密、计算机病毒分析等。
### 2.3.3 高级语言(相当于人类的信息时代)
* `高级语言`是一种`接近于人们使用习惯`的程序设计语言。`它允许程序员使用接近日常英语的指令来编写程序`,程序中的符号和算式也和`日常使用的数学公式`差不多,接近于自然语言和数学语言,容易被人们掌握。
![](./assets/18.png)
* 高级语言`独立于计算机硬件`,有一定的通用性;计算机不能直接识别和执行用高级语言编写的程序,需要使用`编译器``解释器`转换为机器语言,才能被计算机识别和执行。
![](./assets/19.png)
> [!NOTE]
>
> 普遍使用的高级编程语言C、C++、Java、Python、C#、JavaScript、Go、SQL 等。
### 2.3.4 总结
* 编写语言的对比,如下所示:
| 类别 | 特征 | 优点 | 缺点 | 示例 |
| :----------- | :--------------------------------- | :----------------------------------------------- | :----------------------------------------------------------- | :------------------ |
| **机器语言** | 直接由计算机执行的二进制代码 | 执行速度快 | 编写困难,可读性差,与具体硬件强绑定 | 二进制代码 |
| **汇编语言** | 用助记符代替二进制代码的低级语言 | 相对机器语言更易编写和理解,允许直接控制硬件资源 | 依然需要了解硬件,不够抽象,与具体硬件或平台相关 | MOVADD 等助记符 |
| **高级语言** | 接近人类语言,提供了更高层次的抽象 | 易于编写和维护,可移植性好,支持多种编程范式 | 需要通过编译器或解释器转换为机器语言,可能存在一定的性能损失 | CJava Python 等 |
> [!NOTE]
>
> - ① 这三种编程语言类型从低级到高级提供了不同层次的抽象,以满足不同的编程需求和场景。
> - ② 随着计算机科学的发展,高级语言因其强大的表达能力、良好的可移植性和易用性,成为了日常软件开发的主流选择。
# 第三章:初识 C 语言
## 3.1 C 语言的由来
* 1969 年,美国贝尔实验室的`肯·汤姆森`Ken Thompson`丹尼斯·里奇`Dennis Ritchie一起开发了 Unix 操作系统。Unix 最初是使用`汇编语言`编写的,依赖于计算机硬件。为了程序的`可读性``可移植性`,它们决定使用高级语言重写。但是。当时的高级语言无法满足他们的要求,`肯·汤姆森`就在 BCPL 语言的基础上发明了 `B` 语言。
* 1972 年,`丹尼斯·里奇`Dennis Ritchie`B` 语言的基础上重新设计了一种新的语言,这种新语言取代了 `B` 语言,即 `C` 语言。
![](./assets/20.png)
* 1973 年,`整个 Unix 系统都使用 C 语言重写`
> [!NOTE]
>
> C 语言最初是作为 Unix 系统的开发工具而发明的。
* 此后这种语言快速流传广泛用于各种操作系统和系统软件的开发Unix、MS-DOS、Microsoft Windows 以及 Linux 等。
![](./assets/21.png)
* 1988 年美国国家标准协会ANSI正式将 `C 语言标准化`,标志着 C 语言开始稳定和规范化。
## 3.2 为什么要学习 C 语言?
* ① `C 语言具有可移植好、跨平台的特点`:用 C 语言编写的代码可以在不同的操作系统和硬件平台上编译和运行。
> [!NOTE]
>
> * ① C 语言的最原始的设计目的,就是为了将 Unix 操作系统移植到其他的计算机架构上,这使得它从一开始就非常注重可移植性。
> * ② 这边所说的 C 语言的可移植性,是和汇编语言相比的;如果 C 语言和现代化的高级编程语言相比可移植性还是很差的Java 的口号是“一次编译到处运行”Go 的口号是“一次编译,到处执行”。
* ② `C 语言在许多领域应用广泛`
* `操作系统`C 广泛用于开发操作系统Unix、Linux 和 Windows。
* `嵌入式系统`C 是一种用于开发嵌入式系统(如:微控制器、微处理器和其它电子设备)的流程语言。
* `系统软件`C 用于开发设备驱动程序、编译器和汇编器等系统软件。
* `网络`C 语言广泛用于开发网络应用程序例如Web 服务器、网络协议和网络驱动程序。
* `数据库系统`C 用于开发数据库系统例如Oracle、MySQL 和 PostgreSQL 。
* `游戏`:由于 C 能够处理低级硬件交互,因此经常用于开发计算机游戏。
* `人工智能`C 用于开发人工智能和机器学习的应用程序,例如:神经网络和深度学习算法。
* `科学应用`C 用于开发科学应用程序,例如:仿真软件和数值分析工具。
* `金融应用`C 用于开发股票市场分析和交易系统等金融应用。
* ③ C 语言能够直接对硬件进行操作、管理内存以及和操作系统对话,这使得它是一种非常接近底层的语言,非常适合`写需要和硬件交互、有极高性能要求`的程序。
* ④ `学习 C 语言有助于快速上手其他编程语言`C++(原先是 C 语言的一个扩展,在 C 语言的基础上嫁接了面向对象编程思想、C#、Java 等,这些语言都继承或深受 C 语言的影响和启发。
* ⑤ C 语言长盛不衰。`C 语言至今,依然是最广泛使用、最流行的编程语言之一`,包括很多大学将 C 语言作为计算机教学的入门语言,拥有庞大而活跃的用户社区,这意味着有许多资源和库可供开发人员使用。
## 3.3 计算机语言排行榜
* [TIOBE](https://www.tiobe.com/tiobe-index/) 是一个流行编程语言排行每月更新。排名权重基于世界范围内工程师数量Google、Bing、Yahoo! 、Wikipedia、Amazon、Youtube 和百度这些主流的搜索引擎,也将作为排名权重的参考指标。
![](./assets/22.png)
* 计算机语言走势图:
![](./assets/23.png)
## 3.4 C 语言的版本选择
* 随着微型计算机的日益普及,出现了许多 C 语言版本(标准):
* 版本 1KR CK&R C 指的是 C 语言的原始版本。1978年C 语言的发明者布莱恩·柯林Brian `K`ernighan和丹尼斯·里奇Dennis `R`itchie合写了一本著名的教材《C 编程语言》The C programming language
>[!NOTE]
>
>由于 C 语言还没有成文的语法标准,这本书就成了公认标准,以两位作者的姓氏首字母作为版本简称 “K&R C”。
* 版本 2ANSI C又称 C89 或 C90C 语言的原始版本非常简单,对很多情况的描述非常模糊,加上 C 语法依然在快速发展,要求将 C 语言标准化的呼声越来越高。1989 年美国国家标准协会ANSI制定了一套 C 语言标准并于次年被国际标准化组织ISO通过。它被称为 “ANSI C”也可以按照发布年份称为 “C89 或 C90”。
* 版本 3C99C 语言标准的第一次`大型修订`,发生在 1999 年,增加了许多语言特性,比如:双斜杠( // )的注释语法,可变长度数组、灵活的数组成员、复数、内联函数和指定的初始值设定项,这个版本称为 C99`是目前最流行的 C 版本`
* 版本 4C112011 年,标准化组织再一次对 C 语言进行修订增加了_Generic、static_assert 和原子类型限定符。这个版本称为 C11。
> [!NOTE]
>
> 需要强调的是,修订标准的原因并不是因为原标准不能用,而是需要跟进新的技术。
* 版本 5C17C11 标准在 2017 年进行了修补,但发布是在 2018 年。新版本只是解决了 C11 的一些缺陷,没有引入任何新功能。这个版本称为 C17。
* 版本 6C232023 年发布,计划进一步增强安全性,消除实现定义的行为,引入模块化语言概念等新特性,使 C 语言在安全和可靠性方面有重大提高。
* ……
## 3.5 C 语言的优缺点
* C 语言的优点:
* ① 高效C 语言生成的代码非常高效,执行速度快,这使得其非常适合用于操作系统、嵌入式系统等需要高性能的场景。
* ② 灵活性和低级控制C 语言允许直接操作内存和硬件,可以进行位操作、指针运算等底层编程,非常适合开发需要直接硬件控制的应用。
* ③ 广泛的硬件和平台支持C 语言几乎可以在所有的计算机平台上运行,从微处理器到超级计算机,几乎所有的硬件平台都支持 C 语言。
* ④ 标准库丰富C 语言有一个标准库C Standard Library提供了大量常用的函数涵盖了文件操作、字符串处理、内存管理等多种功能。
* ⑤ 语言简洁:语法规则相对简单,没有过多的复杂特性,使得语言本身比较容易学习和掌握。
* C 语言的缺点:
* ① 缺乏高级特性和现代编程语言相对C 语言缺乏一些高级特性,如:面向对象编程、垃圾回收机制等,这使得某些类型的应用程序开发可能会更加复杂。
* ② 安全性问题C 语言允许直接操作内存,可能会导致缓冲区溢出、空指针引用等安全漏洞。如果不小心处理,容易产生难以调试的错误和安全隐患。
* ③ 手动管理内存C 语言需要程序员手动管理内存,即:分配内存和释放内存,这增加了内存泄露和悬空指针等问题的风险。
* ④ 错误调试困难:由于 C 语言的底层操作特点,调试和排查错误可能比较困难,尤其是在处理复杂指针和内存操作的时候。
* ⑤ 标准库有限:虽然 C 语言的标准库涵盖了很多基本功能,但相比现代编程语言的标准库,功能相对有限,尤其是在网络编程、多线程编程等方面。
* 总而言之C 语言的高效性和灵活性使其在系统级编程和嵌入式系统中占据重要地位但其缺乏高级特性和内存管理上的挑战也使得开发过程可能更加复杂和容易出错。对于需要高性能和底层控制的应用C 语言依然是不可替代的选择。
# 第四章C 语言的学习技巧
## 4.1 概述
* 对于大部分的初学者, 学习 C 语言的目的可能是为了成为一名合格的程序员,开发出优秀的软件。但是,在学习了 C 语言的基本语法后,却发现只能在`控制台``黑底白字`)上玩玩,没有漂亮的用户界面以及人性化的交互。于是,开始学习数据结构、算法、数据库、操作系统,越陷越深,越来越迷茫,不知道学习 C 语言能做什么,认为学习编程很难,开始怀疑自己,直到放弃!!!
* 其实C 语言本身就是一门非常简单的语言,提供的实用功能不多,大部分的时候需要`借助`操作系统、第三方库以及以及一些硬件才能发挥它的威力!!!
> [!IMPORTANT]
>
> * ① 学习 C 语言仅仅是让你踏上程序员之路的第一步而已,只学习 C 语言也做不了什么。
> * ② 系统、扎实的学习 C 语言可以让你了解底层硬件、一些简单的数据结构和算法,并培养计算机思维。
* C 语言是一门通用性的语言并没有针对某个领域进行优化在实际项目中C 语言主要用于比较底层的开发,例如:
* Windows、Linux、Unix 等操作系统的内核 90% 以上都使用 C 语言开发Rust 语言有望未来,在更多的操作系统开发中占据一席之地,特别是在对安全性和性能要求极高的领域)。
* 开发硬件驱动,让硬件和操作系统连接起来,这样用户才能更有效的使用硬件。
* 单片机和嵌入式属于软硬件的结合,是使用 C 语言最多的地方。
* 开发系统组件或服务,用于支撑上层应用。
* ……
* 既然 C 语言的应用很多,为什么感觉学习它还是做不了什么?答案就是`生态`
> [!IMPORTANT]
>
> 现代化的高级编程语言的流行程度,除了和编程语言的设计是否优秀有关,最主要的原因就是`生态`
>
> * ① 很多编程语言都自带`标准库`语言本身提供的开箱即用Java、Go 等。
> * ② 很多编程语言都有自己的`包管理器`用于管理第三方库解决方案Java 中的 Maven、Gradle、Go 中的 go modules JavaScript 的 npm 等。
>
> 遗憾的是C 语言的`标准库`非常简单,只有`输入输出``文件操作``日期时间``字符串处理``内存管理`,对于`网络编程``GUI``数据库``并发``需要`大量的`第三方库`来扩展 C 语言的功能Java 语言、Go 语言等其他的现代化高级编程语言都是直接将这些常见的开发场景内置到标准库中极大的降低了软件开发的难度。C 语言的`第三方库`也非常稀少,更别提缺少自己的包管理器。
>
> 不过,现在 C 语言社区也开始诞生了一些包管理器Conan 和 vcpkg 也有自己的项目构建工具cmake 、xmake 等。
> [!NOTE]
>
> JavaScript 的作者 Brendan Eich布兰登·艾奇 曾经这么说:“与其说我爱 JavaScript不如说我恨它。它是 C 语言和 Self 语言一夜情的产物。十八世纪英国文学家约翰逊博士说得好:"它的优秀之处并非原创,它的原创之处并不优秀。"”
>
> 汇编生 C C 生万物!!!
## 4.2 项目构建工具和包管理器
### 4.2.1 概述
* `项目构建工具``包管理器`在软件开发中扮演着不同的角色,它们虽然有时会有重叠的功能,但主要关注的点是不同的。
### 4.2.2 项目构建工具
* `项目构建工具`是用于`自动化编译、测试、打包、部署`等一系列任务的软件工具。它们帮助开发者简化和管理整个软件开发生命周期中的各个步骤,尤其是在构建过程中的复杂性管理上。
* 其功能有:
* **编译代码**:自动编译源代码(如 `.java``.c` 等)为可执行文件或中间文件(如:`.class` 文件)。
* **运行测试**:集成单元测试、集成测试,自动运行测试用例并生成报告。
* **打包**将编译后的代码、依赖库、资源文件等打包成可分发的格式JAR、WAR、可执行文件等
* **依赖管理**:自动下载、更新和管理项目所需的第三方库(这部分功能有时与包管理器重叠)。
* **部署**:将打包后的应用程序自动部署到测试环境、生产环境等。
* **任务自动化**:除了基本的构建流程外,还可以自动化执行一些常见任务,如:代码检查、文档生成等。
* 常用的项目构建工具:
* **MavenJava**:一个流行的构建工具和依赖管理工具,广泛用于 Java 项目。
* **GradleJava、Kotlin、Groovy**:一个灵活的构建工具,支持声明式的构建脚本和多种语言。
* **MakeC/C++**:一个经典的构建工具,使用 `Makefile` 来定义构建规则和依赖关系。
* ~~**AntJava**:早期流行的 Java 构建工具,通过 XML 配置文件定义构建过程。~~
* **CMakeC/C++**一个跨平台的构建系统帮助生成标准的构建文件Makefile 或 Visual Studio 项目文件。
### 4.2.3 包管理器
* `包管理器`是用于`自动化安装、更新、配置``管理软件包及其依赖关系`的工具。它主要关注于获取和管理项目所需的第三方库或工具包,并确保它们正确地集成到项目中。
* 其功能有:
* **依赖管理**:根据项目配置文件(如:`package.json``requirements.txt`)自动下载和安装项目所需的依赖包。
* **版本控制**:管理包的版本,允许开发者指定某个特定版本或版本范围,确保项目中的库版本一致性。
* **包的发布和共享**:开发者可以通过包管理器发布自己的库,并且共享给社区或组织内部的其他项目使用。
* **环境隔离**:有些包管理器提供虚拟环境功能,可以将不同项目的依赖隔离开,避免版本冲突。
* **更新和卸载**:包管理器可以自动更新依赖包到最新的兼容版本或卸载不再需要的包。
* 常见的包管理器:
* **npmNode.js**:用于管理 JavaScript 和 Node.js 项目的包和模块。
* **pipPython**:用于安装和管理 Python 的软件包。
* **ComposerPHP**:用于管理 PHP 项目的依赖库。
* **NuGet.NET**:用于管理 .NET 平台上的包和库。
* **RubyGemsRuby**:用于管理 Ruby 的库和工具包。
* **CargoRust**Rust 编程语言的包管理器和构建工具。
* **YarnJavaScript**:是 npm 的替代品,提供更快和更可靠的包管理体验。
* **HomebrewmacOS**:用于 macOS 系统下的命令行工具和库的管理。
### 4.2.3 注意事项
* 对于 `Java` 项目中的 `Maven``Gradle` 而言,其不仅是`项目构建工具`也是`包管理工具`

View File

@ -1,558 +1,8 @@
# 第一章:计算机组成原理
# 第一章:开发环境的安装和配置(⭐)
## 1.1 计算机系统
## 1.1 环境的安装和配置
* 计算机Computer俗称`"电脑"`,是一种能够接收和存储信息,并按照存储在其内部的程序对海量的数据进行自动、高速的处理,然后将处理结果输出的现代化智能电子设备。
* 计算机有很多形式,如:台式电脑、笔记本电脑、智能手机、平板电脑等,还有生产环境中提供重要业务支撑的各种服务器。
![](./assets/1.jpg)
* 一个完整的`计算机系统``硬件Hardware系统``软件Software系统`两大部分组成,即:
![](./assets/2.png)
## 1.2 冯·诺依曼体系结构
* `冯·诺依曼`是一位多才多艺的科学家,他在数学、物理学、计算机科学、经济学等领域都有杰出的贡献。
![](./assets/3.jpg)
* `冯·诺依曼`的主要成就:
- 在计算机科学领域的最著名贡献是提出了`冯·诺依曼`体系结构1946 年),这是`现代计算机设计的基础`
- 促进了计算机的可编程性和通用性,使得计算机能够执行各种复杂的任务。
- 对核武器设计、自动化控制系统、人工智能等领域的发展产生了重要影响。
- ……
> [!IMPORTANT]
>
> `冯·诺依曼体系结构`是现代计算机(量子计算机除外)设计的`基础`
* `冯·诺依曼`体系结构的理论要点如下:
- ① **存储程序**`程序指令``数据`都存储在计算机的内存中,这使得程序可以在运行时修改。
- ② **二进制逻辑**:所有`数据``指令`都以`二进制`形式表示。
- ③ **顺序执行**:指令按照它们在内存中的顺序执行,但可以有条件地改变执行顺序。
- ④ **五大部件**:计算机由`运算器``控制器``存储器``输入设备``输出设备`组成。
- ⑤ **指令结构**:指令由操作码和地址码组成,操作码指示要执行的操作,地址码指示操作数的位置。
- ⑥ **中心化控制**计算机的控制单元CPU负责解释和执行指令控制数据流。
![](./assets/4.png)
> [!NOTE]
>
> 上述的组件协同工作,构成了一个完整的计算机系统:
>
> * **运算器**和**控制器**通常被集成在一起组成中央处理器CPU负责数据处理和指令执行。
> * **存储器**保存数据和程序,是计算机运作的基础。
> * **输入设备**和**输出设备**负责与外界的交互,确保用户能够输入信息并接收计算机的处理结果。
## 1.3 各种硬件处理速度和性能优化
* 计算机的性能短板:如果 CPU 有每秒处理 1000 个服务请求的能力,各种总线的负载能力能达到 500 个, 但网卡只能接受 200个请求而硬盘只能负担 150 个的话,那这台服务器得处理能力只能是 150 个请求/ 秒,有 85% 的处理器计算能力浪费了,在计算机系统当中,`硬盘`的读写速率已经成为影响系统性能进一 步提高的瓶颈。
![img](./assets/5.jpg)
* 计算机的各个设备部件的延迟从高到低的排列依次是机械硬盘HDD、固态硬盘SSD、内存、CPU 。
![img](./assets/6.png)
* 从上图中我们可以知道CPU 是最快的,一个时钟周期是 0.3 ns ,内存访问需要 120 ns ,固态硬盘访问需要 50-150 us传统的硬盘访问需要 1-10 ms而网络访问是最慢需要 40 ms 以上。
* 时间的单位换算如下:
```txt
1 秒 = 1000 毫秒,即 1 s = 1000 ms。
1 毫秒 = 1000 微妙,即 1 ms = 1000 us 。
1 微妙 = 1000 纳秒,即 1 us = 1000 ns。
```
* 按照上图,将计算机世界的时间和人类世界的时间进行对比,即:
```txt
如果 CPU 的时钟周期按照 1 秒计算,
那么,内存访问就需要 6 分钟;
那么,固态硬盘就需要 2-6 天;
那么,传统硬盘就需要 1-12 个月;
那么,网络访问就需要 4 年以上。
```
* 所以,对于 CPU 来说,这个世界真的是太慢了!!!
* 其实,中国古代中的文人,通常以`蜉蝣`来表示时间的短暂(和其他生物的寿命比),也是类似的道理,即:
```txt
鹤寿千岁,以极其游,蜉蝣朝生而暮死,尽其乐,盖其旦暮为期,远不过三日尔。
--- 出自 西汉淮南王刘安《淮南子》
```
```txt
寄蜉蝣于天地,渺沧海之一粟。 哀吾生之须臾,羡长江之无穷。
挟飞仙以遨游,抱明月而长终。 知不可乎骤得,托遗响于悲风。
--- 出自 苏轼《赤壁赋》
```
>[!NOTE]
>
>对于`蜉蝣`来说,从早到晚就是一生;而对于我们`人类`而言,却仅仅只是一天。
* 存储器的层次结构CPU 中也有存储器,即:寄存器、高速缓存 L1、L2 和 L3如下所示
![img](./assets/7.png)
>[!NOTE]
>
>上图以层次化的方式,展示了价格信息,揭示了一个真理,即:天下没有免费的午餐(千万不要相信别人会有发财的机会和你共享,人都是自私的,你算个啥?为什么要找你?)
>
>- ① 存储器越往上速度越快,但是价格越来越贵, 越往下速度越慢,但是价格越来越便宜。
>- ② 正是由于计算机各个部件的速度不同,容量不同,价格不同,导致了计算机系统/编程中的各种问题以及相应的解决方案
## 1.4 计算机软件
### 1.4.1 操作系统的来源
* 在上古时期,硬件资源不够丰富,计算机设计的也非常简陋。那个时候,很多应用程序都是直接跑在硬件上的,即:一个计算机只能跑一个应用程序。
![](./assets/8.png)
* 随着技术的发展,硬件越来越丰富,功能也越来越强大,性能也越来越好。这种情况下,如果一台计算机只能跑一个程序,实在是太浪费了。而且,底层硬件不断丰富,应用程序需要对接的硬件也将越来越多,如果每个应用程序都这么干,不显示工作很重复吗?于是,操作系统应运而生了。
![](./assets/9.png)
- 操作系统的功能:
- 硬件驱动。
- 进程管理。
- 内存管理。
- 网络管理。
- 安全管理。
- 文件管理。
* 那么,操作系统的作用,就是这样的,即:
* 对下,管理计算机的硬件资源。
* 对上,提供使用计算机资源的操作方式,有:
* `系统调用`:是一套已经写好的代码接口,应用程序通过调用这些接口来请求操作系统执行特定的硬件操作。它们直接与硬件交互,提供底层功能支持,如:文件操作、进程管理、内存管理等。`开发者`通过系统调用可以实现对底层资源的直接控制,确保程序能够高效、安全地运行。
* `终端命令`:是一种文本命令接口,通过命令行输入各种指令来控制操作系统和软件的行为。终端命令可以执行文件操作、系统配置、网络管理等各种任务。主要针对`开发人员``高级用户`,他们通过命令行可以快速、精确地完成各种操作,提高工作效率。
* `图形用户界面`GUI是通过图形元素窗口、图标、按钮等与用户进行交互的界面。供直观、易用的操作方式使用户能够通过鼠标点击、拖拽等简单操作完成复杂任务。主要面向`普通用户`,降低了计算机操作的门槛,提高了用户体验和工作效率。
![](./assets/10.png)
### 1.4.2 用户态和内核态
* 在现代操作系统中,`用户态User Mode``内核态Kernel Mode`是两种不同的执行模式,它们对系统资源的访问权限有着本质的区别。这种区分是为了提供一个稳定和安全的运行环境,防止用户程序直接操作硬件设备和关键的系统资源,从而可能引起系统的不稳定或安全问题。
![](./assets/11.png)
- 核态Kernel Mode VS 用户态User Mode
| 类型 | 内核态Kernel Mode | 用户态User Mode |
| :----- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| 权限 | 内核态是操作系统代码运行的模式,拥有访问系统全部资源和执行硬件操作的`最高权限`。在这种模式下,操作系统的核心部分可以直接访问内存、硬件设备控制、管理文件系统和网络通信等。 | 用户态是普通应用程序运行的模式,具有`较低`的系统资源访问权限。在用户态,程序不能直接执行硬件操作,必须通过操作系统提供的接口(即系统调用)来请求服务。 |
| 安全性 | 由于内核态具有如此高的权限,因此只有可信的、经过严格审查的操作系统核心组件才被允许在此模式下运行。这样可以保护系统不被恶意软件破坏。 | 用户态为系统提供了一层保护,确保用户程序不能直接访问关键的系统资源,防止系统崩溃和数据泄露。 |
| 功能 | 内核态提供了`系统调用`的接口,允许用户态程序安全地请求使用操作系统提供的服务,比如:文件操作、网络通信、内存管理等。 | 用户态保证了操作系统的稳定性和安全性,同时也使得多个程序可以在相互隔离的环境中同时运行,避免相互干扰。 |
> [!NOTE]
>
> - ① 操作系统通过用户态和内核态的分离,实现了对系统资源的保护和控制。
> - ② 当用户程序需要进行文件读写、网络通信或其他需要操作系统介入的操作时会发生从用户态到内核态的切换。这通过系统调用System Call实现系统调用是用户程序与操作系统内核通信的桥梁。
> - ③ 执行完毕后,系统从内核态返回用户态,继续执行用户程序。
> - ④ 用户态和内核态的这种分离设计是现代操作系统中实现安全、稳定运行的关键机制之一。
* 示例:
```java
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.List;
public class Demo {
public static void writeFile(String filePath, String content) {
Path path = Paths.get(filePath);
try {
Files.write(path, content.getBytes());
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args){
int a = 10; // 用户态
int b = 20; // 用户态
int c = a + b; // 用户态
string filePath = "c:/demo.txt"; // 用户态
string txt = a + b + c; // 用户态
writeFile(filePath, a); // 从用户态切换到内核态完成文件写入
System.out.println(a); // 从内核态切换回用户态
System.out.println(b); // 用户态
System.out.println(c); // 用户态
}
}
```
### 1.4.3 ISA、ABI 和 API
- ISA 、ABI 和 API 的参考模型如下:
![](./assets/12.jpg)
* 在底层,硬件模型以指令集架构 ISA 表示该架构定义了处理器、寄存器、存储器和中断管理的指令集。ISA 是硬件和软件之间的接口,对于操作系统 OS 开发人员 System ISA 和直接管理底层硬件的应用程序 User ISA 的开发人员来说非常重要。
> [!NOTE]
>
> - ① ISA 是计算机体系结构中定义的一组指令它规定了处理器能够执行的操作。ISA 包括指令的编码、寄存器的使用、内存访问模式等。不同的处理器可能有不同的 ISA例如x86、ARM、MIPS 等。
> - ② 在设计一个新的操作系统时,开发者需要确保操作系统能够支持特定的 ISA ,以便在特定的硬件上运行。例如:如果操作系统旨在运行在 ARM 架构的处理器上,那么它必须能够理解和执行 ARM ISA 定义的指令集。
- 应用程序二进制接口 ABI`操作系统层`与由操作系统管理的`应用程序``库`分开。ABI 涵盖了低级数据类型、对齐方式和调用约定等详细信息,并定义了可执行程序的格式。系统调用在此级别定义。此接口允许应用程序和库在实现相同 ABI 的操作系统之间移植。
> [!NOTE]
>
> - ① ABI 是指在二进制级别上应用程序与操作系统、库或应用程序的不同部分之间的接口。它定义了数据类型的大小、布局、对齐方式以及函数调用的约定如参数如何传递、返回值如何处理等。ABI 确保了编译后的二进制文件能够在特定的操作系统和硬件平台上正确地运行。
> - ② 在 windows 上的应用程序的运行格式是:`PE`portable executable格式、`.dll` dynamic link library格式和 `.lib` 格式;而在 Linux 上的应用程序的运行格式是:`ELF`executable and linking format格式、`.so` shared object格式和 `.a` 格式。
> - ③ 在 Linux 中可以通过 `file /bin/ls` 命令查看指定可执行应用程序的 ABI 格式;从而也可以论证,在 Windows 上可以运行的程序,在 Linux 上运行不了。
> - ④ 当开发者在 Linux 系统上编写 C 语言程序并使用特定的编译器GCC编译时编译器会遵循 Linux 平台的 ABI 规范来生成二进制文件。这样,生成的可执行文件就可以在任何遵循相同 ABI 规范的 Linux 系统上运行。
> - ⑤ 如果一个应用程序需要跨平台(操作系统)运行,就需要使用`一套代码,多平台编译`的方式(针对 C 或 C++ 等相同的源代码在不同平台操作系统上使用特定平台的编译器GCC来分别编译成符合自己平台的 ABI 规范的二进制文件。
- 最高级别的抽象由应用程序编程接口 API 表示,它将`应用程序`连接到`库``底层操作系统`
> [!NOTE]
>
> - ① API 是一组预定义的函数、协议和工具用于构建软件和应用程序。API 允许不同的软件系统相互交互它定义了软件组件之间如何相互通信。API 可以是库、框架、协议或服务。
> - ② 在 Web 开发中,开发者可能会使用 JavaScript 的 Fetch API 来与服务器进行通信,获取数据或提交表单。这个 API 提供了一种标准化的方式来发送 HTTP 请求和处理响应,而不需要开发者关心底层的网络协议细节。
### 1.4.4 系统调用System Call和函数库Library Call
* 在现代操作系统中,应用程序都不能直接作用于硬件,而是运行在操作系统之上。
![](./assets/13.png)
- 并且,在上文的图示中,我们也会看到`系统调用System Call``函数库Library Call`的身影,如下:
![](./assets/14.png)
![](./assets/15.png)
* 其实,`系统调用System Call``函数库Library Call`的区别如下:
| 类型 | 系统调用System Call | 函数库Library Call |
| :------- | :----------------------------------------------------------- | :----------------------------------------------------------- |
| 定义 | 系统调用是操作系统提供给程序员的一组接口,这些接口允许用户空间的程序请求操作系统内核提供的服务,比如文件操作、进程控制、通信和内存管理等。 | 函数库调用是指使用高级语言编写的一组预先编译好的函数,这些函数实现了一些常用的功能,比如:字符串处理、数学计算等。程序员可以在自己的程序中直接调用这些函数,而无需重新实现它们。 |
| 权限 | 执行系统调用时,会从用户态切换到内核态。这是因为系统调用涉及到访问受保护的系统资源,这些操作必须由操作系统控制以确保系统的稳定性和安全性。 | 函数库调用通常在用户态执行,不涉及到用户态与内核态之间的切换。它们直接使用操作系统通过系统调用提供的服务,或者完全在用户空间内完成计算,不需要操作系统介入。 |
| 性能开销 | 由于涉及到用户态与内核态之间的切换,系统调用的执行成本相对较高。因此,频繁的系统调用可能会影响程序的性能。 | 相对于系统调用,函数库调用的性能开销较小。因为它们通常不涉及到模式切换,且执行的操作多在用户空间完成。 |
| 示例 | open()read()write()fork()exec() 等 UNIX/Linux 系统调用。 | C 标准库中的 printf() 等函数;数学库中的 sin()cos() 等函数。 |
> [!NOTE]
>
> - ① **执行层级**:系统调用直接与操作系统内核交互,执行更底层的操作;而函数库调用运行在用户空间,通常使用系统调用来实现其功能。
> - ② **性能开销**:系统调用由于涉及到用户态与内核态的切换,性能开销相对较大;函数库调用则因为主要在用户态执行,性能开销较小。
> - ③ **使用目的**:系统调用提供了访问操作系统资源和服务的能力;函数库调用则提供了方便、高效执行常见任务的手段。
# 第二章:初识计算机语言
## 2.1 计算机语言是什么?
* `人类语言`是人和人之间用于沟通的一种方式,例如:中国人和中国人之间使用普通话沟通,而中国人和美国人交流,则可以使用英语。
* `计算机编程语言`是人和计算机交流的方式。人们可以使用`编程语言`对计算机下达`命令(指令)`,让计算机完成人们需要的功能。
> [!NOTE]
>
> 计算机语言有很多种C、C++、Java、Go、JavaScript、Python、Scala 等。
## 2.2 为什么要学习计算机语言?
* 编程语言到底是什么?编程语言就是由文字和符号组成的,如:
```c
#include <stdio.h> // 这是编译预处理指令
int main() { // 定义主函数
printf("你好,世界!!!"); // 输出所指定的一行信息
return 0; // 函数执行完毕时返回函数值0
}
```
* 编程语言就是用于控制计算机,让其完成我们需要的功能。而我们学习编程语言,其实就是学习这些文字和符号编写的规则。
* 因为 CPU 只能识别二进制的指令,而我们`编写`的程序叫做`源代码`,是人类能看懂;但是,计算机却不能识别。那么,我们就需要让计算机能识别我们编写的源程序,就需要将我们编写的源代码交给编译器程序,其会帮助我们将所编写的源代码转换为计算机能够识别的二进制指令。
> [!NOTE]
>
> 编译器就是运行在操作系统之上的程序,其作用就是用来将程序员编写的源代码转换为计算机能够识别的二进制指令。
* 如果我们用 Java 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Java 语言的编译器将 Java 程序编译为计算机能够识别的二进制指令。
* 如果我们用 Python 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Python 语言的编译器将 Python 程序编译为计算机能够识别的二进制指令。
* ……
* 总而言之,无论我们学习任何一门编程语言,想要将程序运行起来,都必须做如下的两件事情:
* ① 学习该语言的文字和符号编写的规则,即:`语法规则`
* ② 需要在操作系统上安装对应编程语言的`编译器`程序,将源程序编译为计算机能够识别的二进制指令。
## 2.3 计算机语言简史
### 2.3.1 机器语言(相当于人类的石器时代)
* 1946 年 2 月 14 日,世界上第一台计算机 `ENIAC` 诞生,使用的是最原始的`穿透卡片`
![](./assets/16.png)
* 这种卡片使用的是用`二进制代码`表示的语言,和人类语言差别极大,这种语言就称为`机器语言`,如:
```txt
0000,0000,000000010000 代表 LOAD A, 16
0000,0001,000000000001 代表 LOAD B, 1
0001,0001,000000010000 代表 STORE B, 16
```
* 这种语言本质上是计算机能识别的`唯一语言`,人类很难理解;换言之,当时的程序员 99.9% 都是异类!!!
> [!IMPORTANT]
>
> 不同类型CPU 架构x86_64、arm 等的处理器有不同的机器语言指令集指令集架构ISA决定了机器语言的具体形式换言之机器语言与特定硬件架构紧密相关机器语言程序几乎没有可移植性。
### 2.3.2 汇编语言(相当于人类的青铜&铁器时代)
* `汇编语言`使用`助记符`MOV、ADD、SUB代替二进制操作码使程序更易于人类编写和理解因此`汇编语言`也被称为`符号语言`
![](./assets/17.png)
* 汇编语言的`优点`是能编写`高效率`的程序;但是,`缺点`和机器语言没什么不同,汇编语言同样`依赖于具体的计算机架构(面向机器)`,程序不具备跨平台的可移植性。
> [!NOTE]
>
> 汇编语言,目前仍然应用于工业电子编程领域、软件的加密解密、计算机病毒分析等。
### 2.3.3 高级语言(相当于人类的信息时代)
* `高级语言`是一种`接近于人们使用习惯`的程序设计语言。`它允许程序员使用接近日常英语的指令来编写程序`,程序中的符号和算式也和`日常使用的数学公式`差不多,接近于自然语言和数学语言,容易被人们掌握。
![](./assets/18.png)
* 高级语言`独立于计算机硬件`,有一定的通用性;计算机不能直接识别和执行用高级语言编写的程序,需要使用`编译器``解释器`转换为机器语言,才能被计算机识别和执行。
![](./assets/19.png)
> [!NOTE]
>
> 普遍使用的高级编程语言C、C++、Java、Python、C#、JavaScript、Go、SQL 等。
### 2.3.4 总结
* 编写语言的对比,如下所示:
| 类别 | 特征 | 优点 | 缺点 | 示例 |
| :----------- | :--------------------------------- | :----------------------------------------------- | :----------------------------------------------------------- | :------------------ |
| **机器语言** | 直接由计算机执行的二进制代码 | 执行速度快 | 编写困难,可读性差,与具体硬件强绑定 | 二进制代码 |
| **汇编语言** | 用助记符代替二进制代码的低级语言 | 相对机器语言更易编写和理解,允许直接控制硬件资源 | 依然需要了解硬件,不够抽象,与具体硬件或平台相关 | MOVADD 等助记符 |
| **高级语言** | 接近人类语言,提供了更高层次的抽象 | 易于编写和维护,可移植性好,支持多种编程范式 | 需要通过编译器或解释器转换为机器语言,可能存在一定的性能损失 | CJava Python 等 |
> [!NOTE]
>
> - ① 这三种编程语言类型从低级到高级提供了不同层次的抽象,以满足不同的编程需求和场景。
> - ② 随着计算机科学的发展,高级语言因其强大的表达能力、良好的可移植性和易用性,成为了日常软件开发的主流选择。
# 第三章:初识 C 语言
## 3.1 C 语言的由来
* 1969 年,美国贝尔实验室的`肯·汤姆森`Ken Thompson`丹尼斯·里奇`Dennis Ritchie一起开发了 Unix 操作系统。Unix 最初是使用`汇编语言`编写的,依赖于计算机硬件。为了程序的`可读性``可移植性`,它们决定使用高级语言重写。但是。当时的高级语言无法满足他们的要求,`肯·汤姆森`就在 BCPL 语言的基础上发明了 `B` 语言。
* 1972 年,`丹尼斯·里奇`Dennis Ritchie`B` 语言的基础上重新设计了一种新的语言,这种新语言取代了 `B` 语言,即 `C` 语言。
![](./assets/20.png)
* 1973 年,`整个 Unix 系统都使用 C 语言重写`
> [!NOTE]
>
> C 语言最初是作为 Unix 系统的开发工具而发明的。
* 此后这种语言快速流传广泛用于各种操作系统和系统软件的开发Unix、MS-DOS、Microsoft Windows 以及 Linux 等。
![](./assets/21.png)
* 1988 年美国国家标准协会ANSI正式将 `C 语言标准化`,标志着 C 语言开始稳定和规范化。
## 3.2 为什么要学习 C 语言?
* ① `C 语言具有可移植好、跨平台的特点`:用 C 语言编写的代码可以在不同的操作系统和硬件平台上编译和运行。
> [!NOTE]
>
> C 语言的最原始的设计目的,就是为了将 Unix 操作系统移植到其他的计算机架构上,这使得它从一开始就非常注重可移植性。
* ② `C 语言在许多领域应用广泛`
* `操作系统`C 广泛用于开发操作系统Unix、Linux 和 Windows。
* `嵌入式系统`C 是一种用于开发嵌入式系统(如:微控制器、微处理器和其它电子设备)的流程语言。
* `系统软件`C 用于开发设备驱动程序、编译器和汇编器等系统软件。
* `网络`C 语言广泛用于开发网络应用程序例如Web 服务器、网络协议和网络驱动程序。
* `数据库系统`C 用于开发数据库系统例如Oracle、MySQL 和 PostgreSQL 。
* `游戏`:由于 C 能够处理低级硬件交互,因此经常用于开发计算机游戏。
* `人工智能`C 用于开发人工智能和机器学习的应用程序,例如:神经网络和深度学习算法。
* `科学应用`C 用于开发科学应用程序,例如:仿真软件和数值分析工具。
* `金融应用`C 用于开发股票市场分析和交易系统等金融应用。
* ③ C 语言能够直接对硬件进行操作、管理内存以及和操作系统对话,这使得它是一种非常接近底层的语言,非常适合`写需要和硬件交互、有极高性能要求`的程序。
* ④ `学习 C 语言有助于快速上手其他编程语言`C++(原先是 C 语言的一个扩展,在 C 语言的基础上嫁接了面向对象编程思想、C#、Java 等,这些语言都继承或深受 C 语言的影响和启发。
* ⑤ C 语言长盛不衰。`C 语言至今,依然是最广泛使用、最流行的编程语言之一`,包括很多大学将 C 语言作为计算机教学的入门语言,拥有庞大而活跃的用户社区,这意味着有许多资源和库可供开发人员使用。
## 3.3 计算机语言排行榜
* [TIOBE](https://www.tiobe.com/tiobe-index/) 是一个流行编程语言排行每月更新。排名权重基于世界范围内工程师数量Google、Bing、Yahoo! 、Wikipedia、Amazon、Youtube 和百度这些主流的搜索引擎,也将作为排名权重的参考指标。
![](./assets/22.png)
* 计算机语言走势图:
![](./assets/23.png)
## 3.4 C 语言的版本选择
* 随着微型计算机的日益普及,出现了许多 C 语言版本(标准)。
* 版本 1KR CK&R C 指的是 C 语言的原始版本。1978年C 语言的发明者布莱恩·柯林Brian `K`ernighan和丹尼斯·里奇Dennis `R`itchie合写了一本著名的教材《C 编程语言》The C programming language
>[!NOTE]
>
>由于 C 语言还没有成文的语法标准,这本书就成了公认标准,以两位作者的姓氏首字母作为版本简称 “K&R C”。
* 版本 2ANSI C又称 C89 或 C90C 语言的原始版本非常简单,对很多情况的描述非常模糊,加上 C 语法依然在快速发展,要求将 C 语言标准化的呼声越来越高。1989 年美国国家标准协会ANSI制定了一套 C 语言标准并于次年被国际标准化组织ISO通过。它被称为 “ANSI C”也可以按照发布年份称为 “C89 或 C90”。
* 版本 3C99C 语言标准的第一次`大型修订`,发生在 1999 年,增加了许多语言特性,比如:双斜杠( // )的注释语法,可变长度数组、灵活的数组成员、复数、内联函数和指定的初始值设定项,这个版本称为 C99`是目前最流行的 C 版本`
* 版本 4C112011 年,标准化组织再一次对 C 语言进行修订增加了_Generic、static_assert 和原子类型限定符。这个版本称为 C11。
> [!NOTE]
>
> 需要强调的是,修订标准的原因并不是因为原标准不能用,而是需要跟进新的技术。
* 版本 5C17C11 标准在 2017 年进行了修补,但发布是在 2018 年。新版本只是解决了 C11 的一些缺陷,没有引入任何新功能。这个版本称为 C17。
* 版本 6C232023 年发布,计划进一步增强安全性,消除实现定义的行为,引入模块化语言概念等新特性,使 C 语言在安全和可靠性方面有重大提高。
* ……
* 需要注意的是C 语言的标准并没有强制性的约束,只是个说明文档而已。不同的编译器产商,对 C 语言的标准有不同的实现,甚至会出现某些 C 语言的标准在这个编译器下实现了;但是,在另外的编辑器下却没有实现,导致编译程序错误的现象。常见的 C/C++ 编译器如下:
* Borland C++ 宝蓝公司。
* Intel C++ 英特尔编译器。
* MSVC 微软公司。
* g++ 编译器GCC编译套件, Linux 操作系统。
> [!IMPORTANT]
>
> GCC 编译套件对标准的支持是最好的;所以,在实际项目开发中,我们首先会选用 GCC 编译套件来进行开发。
## 3.5 C 语言的优缺点
* C 语言的优点:
* ① 高效C 语言生成的代码非常高效,执行速度快,这使得其非常适合用于操作系统、嵌入式系统等需要高性能的场景。
* ② 灵活性和低级控制C 语言允许直接操作内存和硬件,可以进行位操作、指针运算等底层编程,非常适合开发需要直接硬件控制的应用。
* ③ 广泛的硬件和平台支持C 语言几乎可以在所有的计算机平台上运行,从微处理器到超级计算机,几乎所有的硬件平台都支持 C 语言。
* ④ 标准库丰富C 语言有一个标准库C Standard Library提供了大量常用的函数涵盖了文件操作、字符串处理、内存管理等多种功能。
* ⑤ 语言简洁:语法规则相对简单,没有过多的复杂特性,使得语言本身比较容易学习和掌握。
* C 语言的缺点:
* ① 缺乏高级特性和现代编程语言相对C 语言缺乏一些高级特性,如:面向对象编程、垃圾回收机制等,这使得某些类型的应用程序开发可能会更加复杂。
* ② 安全性问题C 语言允许直接操作内存,可能会导致缓冲区溢出、空指针引用等安全漏洞。如果不小心处理,容易产生难以调试的错误和安全隐患。
* ③ 手动管理内存C 语言需要程序员手动管理内存,即:分配内存和释放内存,这增加了内存泄露和悬空指针等问题的风险。
* ④ 错误调试困难:由于 C 语言的底层操作特点,调试和排查错误可能比较困难,尤其是在处理复杂指针和内存操作的时候。
* ⑤ 标准库有限:虽然 C 语言的标准库涵盖了很多基本功能,但相比现代编程语言的标准库,功能相对有限,尤其是在网络编程、多线程编程等方面。
* 总而言之C 语言的高效性和灵活性使其在系统级编程和嵌入式系统中占据重要地位但其缺乏高级特性和内存管理上的挑战也使得开发过程可能更加复杂和容易出错。对于需要高性能和底层控制的应用C 语言依然是不可替代的选择。
## 3.6 C 语言的学习技巧
* 对于大部分的初学者, 学习 C 语言的目的可能是为了成为一名合格的程序员,开发出优秀的软件。但是,在学习了 C 语言的基本语法后,却发现只能在`控制台``黑底白字`)上玩玩,没有漂亮的用户界面以及人性化的交互。于是,开始学习数据结构、算法、数据库、操作系统,越陷越深,越来越迷茫,不知道学习 C 语言能做什么,认为学习编程很难,开始怀疑自己,直到放弃!!!
* 其实C 语言本身就是一门非常简单的语言,提供的实用功能不多,大部分的时候需要`借助`操作系统、第三方库以及以及一些硬件才能发挥它的威力!!!
> [!IMPORTANT]
>
> * ① 学习 C 语言仅仅是让你踏上程序员之路的第一步而已,只学习 C 语言也做不了什么。
> * ② 系统、扎实的学习 C 语言可以让你了解底层硬件、一些简单的数据结构和算法,并培养计算机思维。
* C 语言是一门通用性的语言并没有针对某个领域进行优化在实际项目中C 语言主要用于比较底层的开发,例如:
* Windows、Linux、Unix 等操作系统的内核 90% 以上都使用 C 语言开发Rust 语言有望未来,在更多的操作系统开发中占据一席之地,特别是在对安全性和性能要求极高的领域)。
* 开发硬件驱动,让硬件和操作系统连接起来,这样用户才能更有效的使用硬件。
* 单片机和嵌入式属于软硬件的结合,是使用 C 语言最多的地方。
* 开发系统组件或服务,用于支撑上层应用。
* ……
* 既然 C 语言的应用很多,为什么感觉学习它还是做不了什么?答案就是`生态`
> [!IMPORTANT]
>
> 现代化的高级编程语言的流行程度,除了和编程语言的设计是否优秀有关,最主要的原因就是`生态`
>
> * ① 很多编程语言都自带`标准库`语言本身提供的开箱即用Java、Go 等。
> * ② 很多编程语言都有自己的`包管理器`用于管理第三方库解决方案Java 中的 Maven、Gradle、Go 中的 go modules JavaScript 的 npm 等。
>
> 遗憾的是C 语言的`标准库`非常简单,只有`输入输出``文件操作``日期时间``字符串处理``内存管理`,对于`网络编程``GUI``数据库``并发``需要`大量的`第三方库`来扩展 C 语言的功能Java 语言、Go 语言等其他的现代化高级编程语言都是直接将这些常见的开发场景内置到标准库中极大的降低了软件开发的难度。C 语言的`第三方库`也非常稀少,更别提缺少自己的包管理器。
>
> 不过,现在 C 语言社区也开始诞生了一些包管理器Conan 和 vcpkg 也有自己的项目构建工具cmake 、xmake 等。
> [!NOTE]
>
> JavaScript 的作者 Brendan Eich布兰登·艾奇 曾经这么说:“与其说我爱 JavaScript不如说我恨它。它是 C 语言和 Self 语言一夜情的产物。十八世纪英国文学家约翰逊博士说得好:"它的优秀之处并非原创,它的原创之处并不优秀。"”
>
> 汇编生 C C 生万物!!!
## 3.7 项目构建工具和包管理器
### 3.7.1 概述
* `项目构建工具``包管理器`在软件开发中扮演着不同的角色,它们虽然有时会有重叠的功能,但主要关注的点是不同的。
### 3.7.2 项目构建工具
* `项目构建工具`是用于`自动化编译、测试、打包、部署`等一系列任务的软件工具。它们帮助开发者简化和管理整个软件开发生命周期中的各个步骤,尤其是在构建过程中的复杂性管理上。
* 其功能有:
* **编译代码**:自动编译源代码(如 `.java``.c` 等)为可执行文件或中间文件(如:`.class` 文件)。
* **运行测试**:集成单元测试、集成测试,自动运行测试用例并生成报告。
* **打包**将编译后的代码、依赖库、资源文件等打包成可分发的格式JAR、WAR、可执行文件等
* **依赖管理**:自动下载、更新和管理项目所需的第三方库(这部分功能有时与包管理器重叠)。
* **部署**:将打包后的应用程序自动部署到测试环境、生产环境等。
* **任务自动化**:除了基本的构建流程外,还可以自动化执行一些常见任务,如:代码检查、文档生成等。
* 常用的项目构建工具:
* **MavenJava**:一个流行的构建工具和依赖管理工具,广泛用于 Java 项目。
* **GradleJava、Kotlin、Groovy**:一个灵活的构建工具,支持声明式的构建脚本和多种语言。
* **MakeC/C++**:一个经典的构建工具,使用 `Makefile` 来定义构建规则和依赖关系。
* ~~**AntJava**:早期流行的 Java 构建工具,通过 XML 配置文件定义构建过程。~~
* **CMakeC/C++**一个跨平台的构建系统帮助生成标准的构建文件Makefile 或 Visual Studio 项目文件。
### 3.7.3 包管理器
* `包管理器`是用于`自动化安装、更新、配置``管理软件包及其依赖关系`的工具。它主要关注于获取和管理项目所需的第三方库或工具包,并确保它们正确地集成到项目中。
* 其功能有:
* **依赖管理**:根据项目配置文件(如:`package.json``requirements.txt`)自动下载和安装项目所需的依赖包。
* **版本控制**:管理包的版本,允许开发者指定某个特定版本或版本范围,确保项目中的库版本一致性。
* **包的发布和共享**:开发者可以通过包管理器发布自己的库,并且共享给社区或组织内部的其他项目使用。
* **环境隔离**:有些包管理器提供虚拟环境功能,可以将不同项目的依赖隔离开,避免版本冲突。
* **更新和卸载**:包管理器可以自动更新依赖包到最新的兼容版本或卸载不再需要的包。
* 常见的包管理器:
* **npmNode.js**:用于管理 JavaScript 和 Node.js 项目的包和模块。
* **pipPython**:用于安装和管理 Python 的软件包。
* **ComposerPHP**:用于管理 PHP 项目的依赖库。
* **NuGet.NET**:用于管理 .NET 平台上的包和库。
* **RubyGemsRuby**:用于管理 Ruby 的库和工具包。
* **CargoRust**Rust 编程语言的包管理器和构建工具。
* **YarnJavaScript**:是 npm 的替代品,提供更快和更可靠的包管理体验。
* **HomebrewmacOS**:用于 macOS 系统下的命令行工具和库的管理。
### 3.7.3 注意事项
* 对于 `Java` 项目中的 `Maven``Gradle` 而言,其不仅是`项目构建工具`也是`包管理工具`
# 第四章C 语言入门Hello World
## 4.1 环境的安装和配置
### 4.1.1 概述
### 1.1.1 概述
* 要开发 C/C++ 程序,需要安装 C/C++ 编译器,目前有两种主流实现,即:
* GCCGNU Compiler Collection全平台实现即支持 Windows、MacOS、Linux 等。
@ -578,9 +28,9 @@ int main() { // 定义主函数
> * ① MinGW-w64 、Cygwin 以及 MSYS2 任选其一安装即可。
> * ② 目前的 Win10 和 Win11 版本支持 WSL2 Windows Sub Linux 2 ,即 Windows 的子系统 Linux可以实现在 Windows 系统上安装一个 Linux ,然后再运行 Linux 中的 GCC 工具链。
### 4.1.2 MinGW-w64 的安装和配置
### 1.1.2 MinGW-w64 的安装和配置
#### 4.1.2.1 安装
#### 1.1.2.1 安装
* 下载到本地:略。
@ -598,7 +48,7 @@ int main() { // 定义主函数
>
> 本人的解压目录是:`D:\develop\mingw64`
#### 4.1.2.2 配置 path 环境变量
#### 1.1.2.2 配置 path 环境变量
* 配置环境变量,以便任意目录都可以执行 gcc 命令,即:
@ -626,9 +76,9 @@ gcc --version
![](./assets/32.gif)
### 4.1.3 Cygwin 的安装和配置
### 1.1.3 Cygwin 的安装和配置
#### 4.1.3.1 安装
#### 1.1.3.1 安装
* 下载到本地:略。
@ -678,13 +128,13 @@ gcc --version
![](./assets/50.png)
#### 4.1.3.2 配置 path 环境变量
#### 1.1.3.2 配置 path 环境变量
* 和 `3.1.2.2 配置 path 环境变量` 步骤相同:略。
### 4.1.4 MSYS2推荐
### 1.1.4 MSYS2推荐
#### 4.1.4.1 安装
#### 1.1.4.1 安装
* 下载到本地:略。
@ -734,19 +184,19 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/59.gif)
#### 4.1.4.2 配置 path 环境变量
#### 1.1.4.2 配置 path 环境变量
* 和 `3.1.2.2 配置 path 环境变量` 步骤相同:略。
## 4.2 IDE 的安装和配置
## 1.2 IDE 的安装和配置
### 4.2.1 CLion
### 1.2.1 CLion
#### 4.2.1.1 概述
#### 1.2.1.1 概述
* [CLion](https://www.jetbrains.com/clion/) 是一款由 JetBrains 推出的跨平台 C/C++ 集成开发环境IDE它具有智能编辑器、CMake 构建支持、调试器、单元测试、代码分析等功能,可以极大提高 C/C++ 开发效率。
#### 4.2.1.2 安装
#### 1.2.1.2 安装
* 鼠标双击,进入安装:
@ -772,7 +222,7 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/65.png)
#### 4.2.1.3 配置
#### 1.2.1.3 配置
* 打开 CLion
@ -818,9 +268,9 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/77.png)
### 4.2.2 VS Code
### 1.2.2 VS Code
#### 4.2.2.1 概述
#### 1.2.2.1 概述
* [Visual Studio Code (VS Code)](https://code.visualstudio.com/) 是一个免费的开源代码编辑器,适用于 Windows、MacOS 和 Linux 平台。它支持语法高亮、智能代码补全IntelliSense、内置调试工具和Git集成。用户可以通过扩展来添加更多功能支持新的编程语言、主题和调试工具。VS Code 还支持在微软 Azure 上进行部署和托管,适用于各种编程语言和框架。
@ -828,7 +278,7 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
>
> Visual Studio Code 需要安装对应的插件,才能运行 C/C++ 代码。
#### 4.2.2.2 安装
#### 1.2.2.2 安装
* 鼠标双击,进入安装:
@ -862,7 +312,7 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/85.png)
#### 4.2.2.3 配置
#### 1.2.2.3 配置
* 安装`中文`插件:
@ -876,9 +326,9 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/89.png)
### 4.2.3 Microsoft Visual Studio
### 1.2.3 Microsoft Visual Studio
#### 4.2.3.1 概述
#### 1.2.3.1 概述
* [Visual Studio](https://visualstudio.microsoft.com/)(简称 VS是由微软公司发布的集成开发环境。它包括了整个软件生命周期中所需要的大部分工具UML工具、代码管控工具、集成开发环境IDE等。
@ -888,7 +338,7 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
* Visual Studio 旨在成为世界上最好的 IDE集成开发环境目前最新版本为 Visual Studio 2022。
#### 4.2.3.2 安装
#### 1.2.3.2 安装
* 鼠标双击,进入安装:
@ -938,7 +388,7 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/101.png)
#### 4.2.3.3 配置
#### 1.2.3.3 配置
* 在开始菜单处,启动 VS
@ -967,9 +417,11 @@ pacman -Sy mingw-w64-x86_64-toolchain --noconfirm # 安装开发 gcc 相关工
![](./assets/107.png)
## 4.3 HelloWorld
### 4.3.1 手动版
# 第二章HelloWorld
### 2.3.1 手动版
* ① 新建一个 `HelloWorld.c` 的文件:
@ -1004,7 +456,7 @@ gcc HelloWorld.c -o HelloWorld.exe
![](./assets/111.gif)
### 4.3.2 VS Code 版
### 2.3.2 VS Code 版
* ① 新建一个`空`文件夹(目录),用于存放代码:
@ -1057,7 +509,7 @@ gcc HelloWorld.c -o HelloWorld.exe
![](./assets/120.gif)
### 4.3.3 VS 版
### 2.3.3 VS 版
* ① 新建空项目:
@ -1096,7 +548,7 @@ int main(){
![](./assets/129.gif)
### 4.3.4 CLion
### 2.3.4 CLion
* ① 新建空项目:
@ -1144,9 +596,9 @@ int main(){
# 第五章:注释
# 第三章:注释(⭐)
## 5.1 概述
## 3.1 概述
* 编程语言中,`注释`是一种`特殊`的文本,它不会被编译器执行,而仅用于代码的解释和文档说明。
@ -1155,7 +607,7 @@ int main(){
>* ① 注释是一个程序员必须有具有的良好编程习惯。
>* ② 在实际开发中,程序员可以将自己的思路通过`注释`整理出来,然后再用`代码`去实现。
## 5.2 单行注释
## 3.2 单行注释
* C 语言中的单行注释的格式,如下所示:
@ -1182,7 +634,7 @@ int main() { // 定义主函数
}
```
## 5.3 多行注释
## 3.3 多行注释
* C 语言中的多行注释的格式,如下所示:
@ -1220,11 +672,11 @@ int main() {
# 第HelloWorld 的规范(⭐)
# 第HelloWorld 的规范(⭐)
## 6.1 规范的代码风格
## 4.1 规范的代码风格
### 6.1.1 正确的缩进和空白
### 4.1.1 正确的缩进和空白
* ① 使用一次 `tab` 操作,实现缩进,默认整体向右边移动;如果使用 `shift + tab` 则整体向左移动。
* ② 运算符两边习惯各加一个空格,如:`2 + 4 = 6`
@ -1252,7 +704,7 @@ int main() {
}
```
### 6.1.2 代码风格
### 4.1.2 代码风格
* 在 C 语言中,有两种代码风格:`行尾风格``次行风格`
@ -1294,9 +746,9 @@ int main()
}
```
## 6.2 代码细节剖析
## 4.2 代码细节剖析
### 6.2.1 main() 函数
### 4.2.1 main() 函数
* 在 C 语言中,一个程序或工程可以定义很多函数,但是有且只有一个 main() 函数,作为程序执行的入口,并且在 main() 函数结尾结束整个程序的运行,即:
@ -1314,14 +766,14 @@ int main(){
> * ① 在 C 语言中,人们约定,如果 `return 0`,就表示 main() 函数终止运行,且运行成功;如果返回其它非零整数,则表示运行失败。
> * ② 默认情况下,如果 main() 函数中省略 `return 0` ,则编译器会自动加上;但是,为了保持统一的代码风格,不建议省略。
### 6.2.2 函数体
### 4.2.2 函数体
* ① 一对花括号 `{}` 定义了函数的主体,所有函数都必须以大括号开头和结尾,成对出现。
* ② C 程序中的函数体指的是作为该函数一部分的语句。它可以是任何操作,比如:搜索、排序、打印等。
* ③ 每一个执行语句后面都会有一个英文分号`;`作为语句结束的标志。
* ④ 一行内可写几条语句,一条语句也可写在几行上。
### 6.2.3 printf() 函数
### 4.2.3 printf() 函数
* printf() 函数的格式,如下所示:
@ -1341,9 +793,9 @@ printf ("Hello World"); // 将字符串输出到控制台,行尾不换行
printf("Hello World\n");
```
### 6.2.4 标准库和头文件
### 4.2.4 标准库和头文件
#### 6.2.4.1 概述
#### 4.2.4.1 概述
* printf() 函数是在标准库的头文件 `stdio.h` 中定义的,要想在程序中使用这个函数,必须在源文件的头部引入该头文件,即:
@ -1351,7 +803,7 @@ printf("Hello World\n");
#include <stdio.h>
```
#### 6.2.4.2 标准库Standard Library
#### 4.2.4.2 标准库Standard Library
* C 语言的`标准库`是由一组函数组成,这些函数提供了许多常用的操作和功能,如:输入输出、字符串处理、内存管理、数学计算等。标准库中的函数由编译器提供,遵循 ANSI C 标准C89/C90、C99、C11等
* 换言之C 语言的`标准库`就是包含函数的实际代码这些代码在编译的时候被链接到我们的程序中无需手动包含。C 语言的`标准库`提供了可重用的函数实现,使得程序员不必编写常用的功能。
@ -1360,7 +812,7 @@ printf("Hello World\n");
>
> 实际的 printf() 函数的实现代码通常位于标准库的实现文件中,如:在 Linux 中的标准库`libc.so.6` 就包含了 printf() 函数的实现。
#### 6.2.4.3 头文件Header Files
#### 4.2.4.3 头文件Header Files
* `头文件`是包含函数声明、宏定义、数据类型定义等内容的文件。头文件的作用是为源代码提供必要的声明和定义,以便编译器能够正确解析和链接函数调用。头文件通常以`.h`作为文件扩展名。
* 换言之,头文件包含函数声明、宏定义和数据类型定义,但不包含函数的实现。头文件告知编译器如何使用标准库中的函数和定义,确保编译时的正确性。头文件需要在源代码文件中使用`#include`指令显式包含,如:`#include <stdio.h>`
@ -1378,7 +830,7 @@ printf("Hello World\n");
| **stdbool.h** | 布尔类型库 | `bool` `true` `false` |
| **assert.h** | 断言库 | `assert` |
#### 6.2.4.4 预处理命令
#### 4.2.4.4 预处理命令
* `#include` 命令的作用是将指定文件的内容插入到包含该命令的源文件中。这通常用于包含头文件,以便使用头文件中声明的函数、宏和数据类型。
* 语法:
@ -1397,11 +849,11 @@ printf("Hello World\n");
# 第CLion 高级配置(⭐)
# 第CLion 高级配置(⭐)
## 7.1 安装和配置 WSL2
## 5.1 安装和配置 WSL2
### 7.1.1 概述
### 5.1.1 概述
* WSL 2全称为 Windows Subsystem for Linux 2是微软提供的一种技术允许用户在 Windows 操作系统上运行 Linux 内核。WSL 2 是 WSL 的升级版,它引入了一个真正的 Linux 内核来代替 WSL 1 中使用的兼容层,从而提供更高的性能和更广泛的系统调用支持。
* 其架构图,如下所示:
@ -1421,7 +873,7 @@ printf("Hello World\n");
* ③ **多平台开发**对于跨平台开发者来说WSL 2 允许他们在一个操作系统上同时进行 Windows 和 Linux 平台的开发和测试,提高工作效率。
* ④ **运行 Linux 工具和应用程序**WSL 2 支持在 Windows 上直接运行各种 Linux 工具和应用程序Docker、数据库、编程语言环境等。
### 7.1.2 WSL2 的安装
### 5.1.2 WSL2 的安装
* ① BIOS 或 UEFI 中,开启虚拟化:步骤略。
@ -1509,7 +961,7 @@ wsl --list
![](./assets/148.gif)
### 7.1.3 配置 WSL2
### 5.1.3 配置 WSL2
* 本人的安装的是 AlmaLinux9 ,所以需要执行如下命令,以便安装 cmake 相关工具链:
@ -1528,7 +980,7 @@ sudo dnf install gdb -y # 安装 gdb
![](./assets/150.gif)
### 7.1.4 配置 WSL2
### 5.1.4 配置 WSL2
* 本人的安装的是 Ubuntu 24.04,所以需要执行如下命令,以便安装 cmake 相关工具链:
@ -1550,13 +1002,13 @@ sudo apt install gdb -y # 安装 gdb
![](./assets/152.gif)
## 7.2 切换 CLion 中的 cmake 的工具链
## 5.2 切换 CLion 中的 cmake 的工具链
* 可以在 CLoin 中切换 cmake 的工具链,以便支持不同平台的 cmake ,即:
![](./assets/153.gif)
## 7.3 修改 CMakeLists.txt 文件
## 5.3 修改 CMakeLists.txt 文件
* 前文也提到了,在一个 C 语言项目中,只能有一个 main() 函数;但是,我们可以修改 `CMakeLists.txt` 文件的内容,以便其支持在一个 C 语言项目中,可以有多个包含 main() 函数的文件,如下所示:
@ -1631,7 +1083,7 @@ foreach (SOURCE ${SOURCES})
endforeach ()
```
## 7.4 配置 .clang-format 文件
## 5.4 配置 .clang-format 文件
* 配置 `.clang-format` 格式化文件,以便写代码的时候,可以自动保存并格式化 C 程序代码,如下所示:
@ -1679,7 +1131,7 @@ SpacesInCStyleCastParentheses: false
![](./assets/156.gif)
## 7.5 配置 .gitignore 文件
## 5.5 配置 .gitignore 文件
* 需要在项目中,配置 `.gitignore` 文件,以便在提交代码到 Git 仓库的时候,忽略某些文件或目录,如下所示:
@ -1694,7 +1146,7 @@ cmake-build-*
build
```
## 7.6 演示
## 5.6 演示
* 我们可以在项目中,临时创建或复制一个文件,看上述配置是否生效,即:
@ -1706,9 +1158,9 @@ build
# 第C 语言的编译过程(⭐)
# 第C 语言的编译过程(⭐)
## 8.1 概述
## 6.1 概述
* C 程序的编译过程,如下所示:
@ -1753,14 +1205,14 @@ build
>
> 如果`修改`了源代码,还需要重新`编译``链接`,并生成新的 `*.exe`文件,再执行,方能生效。
## 8.2 GCC 编译器的介绍
## 6.2 GCC 编译器的介绍
* 编辑器vim 、vscode 等,是指我们用它来编写源程序的(编辑代码),而我们写的代码语句,电脑是不懂的,我们需要把它转成电脑能懂的语句,编译器就是这样的转化工具。换言之,我们用编辑器编写程序,由编译器编译后才可以运行!
* 编译器是将易于编写、阅读和维护的高级计算机语言翻译为计算机能解读、运行的低级机器语言的程序。
* gccGNU Compiler CollectionGNU 编译器套件),是由 GNU 开发的编程语言编译器。gcc 原本作为 GNU 操作系统的官方编译器,现已被大多数类 Unix 操作系统Linux、BSD、Mac OS X 等采纳为标准的编译器gcc 同样适用于微软的 Windows 。
* gcc 最初用于编译 C 语言,随着项目的发展, gcc 已经成为了能够编译 C、C++、Java、Ada、fortran、Object C、Object C++、Go 语言的编译器大家族。
## 8.3 通过 gcc 直接生成可执行文件
## 6.3 通过 gcc 直接生成可执行文件
* 示例:进行预处理、编译、汇编和链接
@ -1770,9 +1222,9 @@ gcc HelloWorld.c -o HelloWorld.exe
![](./assets/160.gif)
## 8.4 通过 gcc 分步编译
## 6.4 通过 gcc 分步编译
### 8.3.1 概述
### 6.3.1 概述
* 预处理命令:
@ -1798,7 +1250,7 @@ gcc -c 源文件.s -o 源文件.o # 在 Linux 中,通常以 .o 结尾;在 Wi
gcc 源文件.o -o 源文件.exe # 在 Linux 中,通常以 .out 结尾;在 Windows 中,通常以 .exe 结尾
```
### 8.4.2 应用示例
### 6.4.2 应用示例
* 示例:只进行预处理
@ -1838,9 +1290,9 @@ gcc HelloWorld.o -o HelloWorld.exe
![](./assets/164.gif)
# 第章:附录
# 第章:附录
## 9.1 WSL2 代理问题
## 7.1 WSL2 代理问题
* 在安装和配置 WSL2 之后,可能会出现如下的提示,即:
@ -1875,7 +1327,7 @@ wsl --shutdown
![](./assets/169.png)
## 9.2 CLion 调试问题
## 7.2 CLion 调试问题
* 在 CLion 中进行 run运行程序的时候对于 `printf` 函数或 `scanf` 函数很正常,如下所示:
@ -1910,9 +1362,9 @@ int main() {
![](./assets/172.gif)
## 9.3 内存泄露检测
## 7.3 内存泄露检测
### 9.3.1 概述
### 7.3.1 概述
* C 语言中的指针是否使用是个颇具争议的话题现代化的高级编程语言通过各种策略和机制在编译期就能解决指针危险的问题。但是遗憾的是C 语言的指针很大程度上,在运行期才会暴露问题。
* 幸运的是,我们可以使用 `Valgrind` 项目来进行`内存泄露检测``性能分析`,而 `Valgrind` 只支持 Linux 。
@ -1921,7 +1373,7 @@ int main() {
>
>win 11 中的 WSL2 就是个 Linux 环境,我们可以在上面跑各种 Linux 工具这样我们就不需要再安装虚拟机软件了VMware Workstation它会完整的模拟一个硬件系统并在上面跑各种 Linux ,实在是太笨重了)。
### 9.3.2 安装
### 7.3.2 安装
* 在 WSL2 上安装 Valgrind
@ -1943,7 +1395,7 @@ which valgrind
![](./assets/174.gif)
### 9.3.3 整合
### 7.3.3 整合
* CLion 中将工具链设置为 WSL2
@ -2038,15 +1490,15 @@ endforeach ()
![](./assets/179.gif)
## 9.4 性能分析
## 7.4 性能分析
### 9.4.1 概述
### 7.4.1 概述
* `perf` 是一个 Linux 下的性能分析工具,主要用于监控和分析系统性能。它可以帮助开发者和系统管理员了解系统中哪些部分在消耗资源、识别性能瓶颈以及分析程序的运行效率。
### 9.4.2 安装
### 7.4.2 安装
#### 9.4.2.1 AlmaLinux9
#### 7.4.2.1 AlmaLinux9
* 在 WSL2 中的 AlmaLinux 安装 perf
@ -2056,7 +1508,7 @@ dnf -y install perf
![](./assets/180.gif)
#### 9.4.2.2 Ubuntu 22.04
#### 7.4.2.2 Ubuntu 22.04
* 在 WSL2 中的 Ubuntu 安装 perf
@ -2144,7 +1596,7 @@ cp perf /usr/bin/
![](./assets/188.gif)
### 9.4.3 整合
### 7.4.3 整合
* CLion 中配置 perf 的路径:
@ -2154,7 +1606,7 @@ cp perf /usr/bin/
![](./assets/190.gif)
## 9.5 Win 中文乱码问题
## 7.5 Win 中文乱码问题
* 前文,我们提及到,在 Win 中,如果出现`中文乱码`问题,就需要去`语言和区别`设置`系统区域`的编码为 UTF-8 但是这样可能会造成其它的软件出现中文乱码问题Xshell 等。
@ -2175,7 +1627,7 @@ cp perf /usr/bin/
![](./assets/194.gif)
## 9.6 CLion 中自动导入头文件
## 7.6 CLion 中自动导入头文件
* 在 CLion 中,最为强大的功能就是直接输入函数,然后让 IDE 帮我们自动导入头文件,包括自定义的头文件,相当实用。