diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\210\235\350\257\206HAL\345\272\223.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\210\235\350\257\206HAL\345\272\223.md"
index 92625c3b..3ce51013 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\210\235\350\257\206HAL\345\272\223.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\210\235\350\257\206HAL\345\272\223.md"
@@ -1,11 +1,13 @@
# 初识HAL
在比较漫长的汇编语言时代,很多程序员都习惯用位操作对底层硬件进行编写,其优点有以下等:
+
- 代码直观
- 代码执行效率高
- 代码体积小
缺点有以下等:
+
- 代码可读性差
- 代码移植性差
- 代码维护性差
@@ -23,6 +25,7 @@ HAL库的设计目的正是为此,从而使开发者更容易地移植和维
![CMSIS结构图](/images/嵌入式/CMSIS架构图.png)
CMSIS包括以下几个关键部分:
+
1. **CMSIS-Core**:提供了一个基本框架,包括用于启动、中断处理、内存管理和异常处理的通用函数。
2. **CMSIS-DSP**:提供了一个数字信号处理(DSP)的软件库,包含了用于信号处理操作的函数。
3. **CMSIS-RTOS**:提供了一个实时操作系统(RTOS)接口,允许开发者选择并集成不同的RTOS实现。
@@ -31,11 +34,10 @@ CMSIS包括以下几个关键部分:
通过使用CMSIS,开发者可以编写与硬件无关的代码,只需针对特定的微控制器进行一些小的修改或配置,就可以在不同的微控制器上运行。这极大地提高了开发效率,并简化了微控制器软件的维护和更新。
-
-
-
## HAL库介绍
+
ST为了方便用户开发STM32芯片开发提供了三种库:
+
1. 标准外设库(Standard Peripheral Libraries):
- ST最早的库,现在还在用
- 目前只兼容 F0/F1/F3/F2/F4/L1 系列
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\257\204\345\255\230\345\231\250\347\274\226\347\250\213.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\257\204\345\255\230\345\231\250\347\274\226\347\250\213.md"
index 67d8cf43..af919db0 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\257\204\345\255\230\345\231\250\347\274\226\347\250\213.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\345\257\204\345\255\230\345\231\250\347\274\226\347\250\213.md"
@@ -18,4 +18,4 @@
寄存器的设计和优化对计算机的性能有着重要影响,因此现代CPU通常会有大量的寄存器,并且会采用各种技术来提高它们的访问速度和效率。
-## 2.
\ No newline at end of file
+## 2
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\346\234\257\350\257\255\350\241\250.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\346\234\257\350\257\255\350\241\250.md"
index c691a79f..082ba590 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\346\234\257\350\257\255\350\241\250.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\346\234\257\350\257\255\350\241\250.md"
@@ -6,6 +6,7 @@
一种专门设计用来满足实时计算需求的操作系统。实时操作系统必须在规定的时间内完成特定任务,以保证系统的正确性和可靠性。实时系统通常分为硬实时(Hard Real-Time)和软实时(Soft Real-Time)系统。
以下是一些RTOS的主要特点:
+
1. **确定性(Determinism)**:
- RTOS提供确定性的任务调度,确保任务能够在预定的时间限制内完成。
2. **任务调度**:
@@ -19,11 +20,13 @@
6. **资源管理**:
- RTOS有效管理CPU时间、内存和其他系统资源,以支持实时任务。
RTOS广泛应用于以下领域:
+
- **嵌入式系统**:如工业控制系统、汽车电子、医疗设备、航空航天等。
- **网络设备**:如路由器、交换机等网络基础设施。
- **消费电子**:如数字电视、智能手机等。
-
+
一些知名的RTOS包括:
+
- VxWorks
- QNX
- RTLinux
@@ -39,10 +42,12 @@ RTOS的选择取决于具体的应用需求,包括任务的实时性要求、
## 板级支持包(Board Support Package,简称 BSP)
一组用于特定硬件平台的软件,它在该硬件平台上提供了硬件抽象层,使得操作系统或者用户应用能够在该硬件平台上运行。基本的BSP包含以下功能:
+
- **硬件初始化代码**:这些代码负责在系统启动时配置硬件组件,如CPU、内存、外设接口等,以确保它们处于正确的状态。
- **设备驱动程序**:将硬件组件向上抽象为面向应用的API,使操作系统和应用程序能够使用其与硬件设备进行交互。
更完善的还包括以下等:
+
- **系统启动代码**:包括引导加载程序(Bootloader)和其他初始化代码,这些代码负责启动操作系统。
- **配置工具和脚本**:用于配置和定制BSP的工具,以适应特定的硬件配置和操作系统需求。
- **调试和测试工具**:帮助开发人员调试和测试硬件与软件接口的工具。
@@ -70,6 +75,7 @@ BSP的主要目的是为了让操作系统和应用程序开发者不必关心
7. **可扩展性**:
- UEFI的设计允许轻松添加新功能,使其能够适应未来的硬件和软件需求。
UEFI的主要组件包括:
+
- **UEFI固件**:这是嵌入在主板上的固件,负责初始化硬件并提供启动服务。
- **UEFI驱动程序**:用于在UEFI环境中操作硬件的软件模块。
- **UEFI Shell**:一个命令行界面,允许用户执行固件级别的操作。
@@ -84,6 +90,7 @@ BSP的主要目的是为了让操作系统和应用程序开发者不必关心
处理器架构是软件和硬件之间交互的桥梁,它决定了软件如何与硬件进行通信和操作。
以下是几种常见的处理器架构:
+
1. **x86架构**:由Intel和AMD公司开发,是最常见的桌面和服务器处理器架构之一。它支持复杂指令集计算机(CISC)和虚拟化技术。
2. **ARM架构**:由ARM Holdings公司开发,主要用于移动设备和嵌入式系统。它支持精简指令集计算机(RISC)架构,并以其低功耗和高能效而闻名。
3. **MIPS架构**:由MIPS Technologies公司开发,是一种精简指令集计算机(RISC)架构。它曾经在许多工作站和服务器中使用,但现在更多地用于嵌入式系统。
@@ -92,6 +99,7 @@ BSP的主要目的是为了让操作系统和应用程序开发者不必关心
6. **RISC-V架构**:是一个开源的指令集架构,旨在成为现代处理器架构的标准。它支持精简指令集计算机(RISC)架构,并以其模块化和可扩展性而受到关注。
处理器架构的选择取决于多种因素,包括性能需求、能效、成本、生态系统支持、兼容性和特定应用场景。例如:
+
- ARM架构因其低功耗和高能效而广泛用于移动设备
- x86架构因其高性能和广泛的应用软件支持而成为桌面和服务器系统的首选
@@ -100,21 +108,24 @@ BSP的主要目的是为了让操作系统和应用程序开发者不必关心
处理器架构的一部分,它定义了处理器可以理解和执行的机器指令的集合。指令集是软件和硬件之间的接口,它规定了处理器可以执行的操作,以及如何通过操作码和操作数来执行这些操作。
指令集可以分为以下几种类型:
+
1. **复杂指令集计算机(CISC)**:这种类型的指令集包含大量的指令,每个指令可以执行多个操作。CISC架构的处理器通常具有复杂的指令解码器,能够解析和执行复杂的指令。这种架构的优点是每个指令可以完成更多的操作,从而减少总的指令数量。然而,复杂的指令解码和执行可能会导致性能下降。
2. **精简指令集计算机(RISC)**:这种类型的指令集包含较少的指令,每个指令只执行一个简单的操作。RISC架构的处理器通常具有简单的指令解码器,能够快速解析和执行简单的指令。这种架构的优点是指令解码和执行速度快,但需要更多的指令来完成复杂的操作。
3. **混合指令集计算机**:这种类型的指令集结合了CISC和RISC的特点,包含一定数量的复杂指令和简单指令。这种架构的处理器可以根据需要使用复杂的指令或简单的指令来执行操作。
-
+
指令集的选择取决于多种因素,包括性能需求、能效、成本、生态系统支持、兼容性和特定应用场景。例如:
+
- CISC架构的处理器因其能够执行复杂操作而广泛用于桌面和服务器系统
- RISC架构的处理器因其简单高效的指令解码和执行而广泛用于移动设备和嵌入式系统
## CMSIS(Cortex Microcontroller Software Interface Standard)
-一个为ARM Cortex-M微控制器系列设计的标准化软件接口。它旨在为开发者提供一个统一的接口,使得在不同ARM Cortex-M微控制器之间移植和复用软件变得更加容易。CMSIS的目的是减少为不同微控制器编写软件的复杂性,并允许开发者更容易地从一个微控制器迁移到另一个微控制器。
+一个为ARM Cortex-M微控制器系列设计的标准化软件接口。它旨在为开发者提供一个统一的接口,使得在不同ARM Cortex-M微控制器之间移植和复用软件变得更加容易。CMSIS的目的是减少为不同微控制器编写软件的复杂性,并允许开发者更容易地从一个微控制器迁移到另一个微控制器。
![CMSIS结构图](/images/嵌入式/CMSIS架构图.png)
CMSIS包括以下几个关键部分:
+
1. **CMSIS-Core**:提供了一个基本框架,包括用于启动、中断处理、内存管理和异常处理的通用函数。
2. **CMSIS-DSP**:提供了一个数字信号处理(DSP)的软件库,包含了用于信号处理操作的函数。
3. **CMSIS-RTOS**:提供了一个实时操作系统(RTOS)接口,允许开发者选择并集成不同的RTOS实现。
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\216\257\345\242\203\346\220\255\345\273\272.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\216\257\345\242\203\346\220\255\345\273\272.md"
index dcf347e0..07f306d2 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\216\257\345\242\203\346\220\255\345\273\272.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\216\257\345\242\203\346\220\255\345\273\272.md"
@@ -22,27 +22,29 @@ Keil操作简单,容易上手,而且可以很方便地进行调试。
### 1.1 工具安装
-1. [ **STM32CubeMX** ](https://www.st.com/en/development-tools/stm32cubemx.html)
-
- ST官方出的一款针对ST的MCU/MPU跨平台的图形化工具,
+1. [**STM32CubeMX**](https://www.st.com/en/development-tools/stm32cubemx.html)
+
+ ST官方出的一款针对ST的MCU/MPU跨平台的图形化工具,
支持在Linux、MacOS、Window系统下开发,其对接的底层接口是HAL库,
另外习惯于寄存器开发的同学们,也可以使用LL库。STM32CubeMX除了集成MCU/MPU的硬件抽象层,
另外还集成了像RTOS,文件系统,USB,网络,显示,嵌入式AI等中间件,这样开发者就能够很轻松的完成MCU/MPU的底层驱动的配置,
留出更多精力开发上层功能逻辑,能够更进一步提高了嵌入式开发效率。
-2. [ **OpenOCD** ](https://github.com/xpack-dev-tools/openocd-xpack/releases)
+2. [**OpenOCD**](https://github.com/xpack-dev-tools/openocd-xpack/releases)
openocd全名叫做Open On-Chip Debugger,是一个自由开放的片上调试工具和编程工具,
目前已经发布到0.11.0版本,目前主流调试器几乎都支持。
-
+
安装好之后,添加环境变量:
![OpenOCD环境变量](/images/嵌入式/OpenOCD环境变量图.png)
在终端输入,进行测试:
+
```shell
openocd
```
+
如果有信息输出如下,那就是装好了。
![OpenOCD检查](/images/嵌入式/OpenOCD检查图.png)
@@ -50,48 +52,49 @@ Keil操作简单,容易上手,而且可以很方便地进行调试。
3. MinGW
Clion需要使用MinGW环境来配置工具链,安装在网上有很多教程,这里就不赘述了。
-
+
安装好之后,添加到环境变量:
![MinGW环境变量](/images/嵌入式/MinGW环境变量图.png)
在终端输入,进行测试:
+
```shell
gcc -v
```
+
如果有信息输出如下,那就是装好了。
![MinGW检查](/images/嵌入式/MinGW检查图.png)
-4. [ **arm-none-eabi-gcc** ](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads)
+4. [**arm-none-eabi-gcc**](https://developer.arm.com/open-source/gnu-toolchain/gnu-rm/downloads)
- > 注:为什么不是gcc?
- >
+ > 注:为什么不是gcc?
+ >
> 在开发stm32的时候,编译工具链要使用gcc-arm-none-eabi,为什么不是gcc呢?
> 这就要说到Win下的交叉编译了,因为我们要在PC机上编译出可以运行在ARM上的程序,
> 使用gcc编译出的是在PC上运行的程序,所以我们要使用gcc-arm-none-eabi进行交叉编译,才能运行在ARM上。
安装好后,添加到环境变量:
![GNU-arm-none-eabi环境变量](/images/嵌入式/GNU-arm-none-eabi环境变量图.png)
-
+
在终端输入,进行测试:
+
```shell
arm-none-eabi-gcc -v
```
+
如果有信息输出如下,那就是装好了。
![GNU-arm-none-eabi检查](/images/嵌入式/GNU-arm-none-eabi检查图.png)
5. CLion
-
- 安装见[ **CLion** ](/杂项/工具和环境/工具/编程工具.md#1-文本编辑器和代码编辑器)
+
+ 安装见[**CLion**](/杂项/工具和环境/工具/编程工具.md#1-文本编辑器和代码编辑器)
配置CLion的工具链,如下:
-
+
![CLion设置工具链](/images/嵌入式/CLion设置工具链图.png)
配置CLion的STM32开发方式,如下:
-
- ![CLion的STM32开发配置](/images/嵌入式/CLion的STM32开发配置图.png)
-
-
+ ![CLion的STM32开发配置](/images/嵌入式/CLion的STM32开发配置图.png)
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\250\213\345\272\217\344\270\213\350\275\275\344\270\216\350\260\203\350\257\225.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\250\213\345\272\217\344\270\213\350\275\275\344\270\216\350\260\203\350\257\225.md"
index 282ef24d..1f082b64 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\250\213\345\272\217\344\270\213\350\275\275\344\270\216\350\260\203\350\257\225.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\345\265\214\345\205\245\345\274\217/\347\250\213\345\272\217\344\270\213\350\275\275\344\270\216\350\260\203\350\257\225.md"
@@ -8,7 +8,6 @@
| 1 | 0 | 系统储存器 | 即是Bootloader固件所在地 |
| 1 | 1 | SRAM储存器 | 在SRAM中调试代码 |
-
## 1. 串口下载
> 在一般的STM32最小系统板上都带有串口下载电路,这里使用STM32F103C8T6板子。
@@ -29,7 +28,6 @@ CH340的上位机接口是一根USB线,连接到电脑的USB口上,而它的
### 1.3 软件下载
-这里使用[ **FlyMCU** ](http://www.mcuisp.com/chinese%20mcuisp%20web/ruanjianxiazai-chinese.htm)串口下载器,
+这里使用[**FlyMCU**](http://www.mcuisp.com/chinese%20mcuisp%20web/ruanjianxiazai-chinese.htm)串口下载器,
### 1.4 ISP原理分析
-
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\350\257\255\346\263\225\345\222\214\346\240\207\345\207\206\345\272\223/34_\344\275\215\346\223\215\344\275\234.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\350\257\255\346\263\225\345\222\214\346\240\207\345\207\206\345\272\223/34_\344\275\215\346\223\215\344\275\234.md"
index c6792dbb..27b375c8 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\350\257\255\346\263\225\345\222\214\346\240\207\345\207\206\345\272\223/34_\344\275\215\346\223\215\344\275\234.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\350\257\255\346\263\225\345\222\214\346\240\207\345\207\206\345\272\223/34_\344\275\215\346\223\215\344\275\234.md"
@@ -9,7 +9,7 @@
- 每一个位存储一个二进制码(记作 **0** 或 **1**)
2. 对于 **整型** 数据来说,每个计算机位对应这个整数二进制表示中的一个位
3. 8 位构成一个 **字节**,因此 ***在常见的实现中***,`int` 类型有 **4** 字节(*32* 位),`long long` 有 **8** 字节(*64* 位)
-4. 关于进制的知识,可以参考 [ **进制** ](/教程/番外/77_关于进制.md)
+4. 关于进制的知识,可以参考 [**进制**](/教程/番外/77_关于进制.md)
### 1.2 整数的二进制表示(以一字节为例)
@@ -27,7 +27,6 @@
> 只能使用 **整型** 数据进行位操作,不能使用 ~~**~~浮点型~~**~~ 数据;
-
### 2.1 位操作的种类
> 下面的例子使用无符号 8 位整数进行演示:
@@ -60,7 +59,7 @@
```C
~(10011010) // 表达式
- 01100101 // 结果值
+ 01100101 // 结果值
```
5. 按位左移 (<<):
@@ -125,12 +124,12 @@ uint32_t flag = 0b1111111100000000000000000000000000000000;
```C
//typedef unsigned char uint8_t;
-
+
uint8_t flag = 0b10101010;
-
+
//定义MASK,0号位为1,其余位为0
uint8_t mask = 0b00000010;
-
+
//掩码操作
flag = flag & mask; //此时 flag = 0b00000010
```
@@ -176,11 +175,11 @@ uint32_t flag = 0b1111111100000000000000000000000000000000;
- 使用 `&` 运算符和掩码,代码如下:
- 以上一节的 **mask**(只有 `1` 号位为 1)为例:
- ```C
+ ```C
uint8_t flag = 0b10101011;
if ((flag & mask) == mask) {
printf("1号位为1。");
- }
+ }
```
根据 **mask** 中为 `1` 的位, 在 **flag** 中只读对应。
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/build.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/build.md"
index 0aefcced..564edab8 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/build.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/build.md"
@@ -8,7 +8,6 @@
[Limine - C Template](https://github.com/limine-bootloader/limine-c-template)
-
## 自制引导用户
通常你们需要的准备工作要求更多,且编写后的操作系统运行的介质非常有限
@@ -23,17 +22,17 @@ github上有很多使用Multiboot的自制OS实例, 可以借鉴其是如何搭
## 目录结构
-```
-┌ target (目标文件目录, 存放编译好等待链接的目标文件)
+```text
+├ target (目标文件目录, 存放编译好等待链接的目标文件)
├ src (源文件目录, 存放操作系统的所有C和汇编源码)
-| ├ boot (存放引导程序的源码文件)
-| ├ kernel (存放内核的核心功能源码文件, 如中断管理, 多进程, 内存管理等)
-| ├ util (存放一些工具函数实现, 如各种数据结构实现,printf实现等)
-| ├ driver (存放内核内置驱动的源码实现)
-| ├ fs (存放文件系统的源码实现)
-| ├ include (存放各种头文件)
-| └ sysapp (存放系统内置程序, 如shell)
-├ isodir (将最终的内核文件以及所有需要的资源文件到这里的最终目标目录, 等待引导实现程序打包成ISO等映像)
+│ ├ boot (存放引导程序的源码文件)
+│ ├ kernel (存放内核的核心功能源码文件, 如中断管理, 多进程, 内存管理等)
+│ ├ util (存放一些工具函数实现, 如各种数据结构实现,printf实现等)
+│ ├ driver (存放内核内置驱动的源码实现)
+│ ├ fs (存放文件系统的源码实现)
+│ ├ include (存放各种头文件)
+│ └ sysapp (存放系统内置程序, 如shell)
+├ isodir (将最终的内核文件以及所有需要的资源文件到这里的最终目标目录, 等待引导实现程序打包成ISO等映像)
├ apps (操作系统内置的应用程序源码, 一般放置移植或自己开发的各种小程序, 如lua解释器, SDL2图形库等)
└ i686_elf_tools (交叉编译工具链)
```
@@ -48,38 +47,38 @@ github上有很多使用Multiboot的自制OS实例, 可以借鉴其是如何搭
```linker
ENTRY(_start)
-
+
SECTIONS
{
-
- . = 2M;
-
- .text BLOCK(4K) : ALIGN(4K)
- {
- code = .; _code = .; __code = .;
- *(.multiboot)
- *(.text)
- }
-
- .rodata BLOCK(4K) : ALIGN(4K)
- {
- *(.rodata)
- }
-
- .data BLOCK(4K) : ALIGN(4K)
- {
- data = .; _data = .; __data = .;
- *(.data)
- }
-
- .bss BLOCK(4K) : ALIGN(4K)
- {
- bss = .; _bss = .; __bss = .;
- *(COMMON)
- *(.bss)
- }
-
- end = .; _end = .; __end = .;
+
+ . = 2M;
+
+ .text BLOCK(4K) : ALIGN(4K)
+ {
+ code = .; _code = .; __code = .;
+ *(.multiboot)
+ *(.text)
+ }
+
+ .rodata BLOCK(4K) : ALIGN(4K)
+ {
+ *(.rodata)
+ }
+
+ .data BLOCK(4K) : ALIGN(4K)
+ {
+ data = .; _data = .; __data = .;
+ *(.data)
+ }
+
+ .bss BLOCK(4K) : ALIGN(4K)
+ {
+ bss = .; _bss = .; __bss = .;
+ *(COMMON)
+ *(.bss)
+ }
+
+ end = .; _end = .; __end = .;
}
```
@@ -91,7 +90,7 @@ SECTIONS
#### 根目录构建脚本
-```Makefile
+```make
clean: # 目录清理
rm target/*
@@ -109,18 +108,18 @@ linker:
#### 子目录脚本示例
-```Makefile
+```make
gcc := /i686_elf_tools/bin/i686-elf-gcc #交叉编译器的路径
incpath_src := ../include/ #头文件目录路径
out_path_src := ../target/ #根据你的子目录相对于根目录的深度编写 ../的个数
obj_dos := $(out_path_src)源文件名.obj ... #填写你所有的源文件对应的目标文件名 (源文件名.obj)
default : $(obj_dos)
-
+
$(out_path_src)%.o : %.c Makefile #C源文件构建
- $(gcc) -I$(incpath_src) -nostdinc -nolibc -nostdlib -fno-builtin -ffreestanding -fno-stack-protector -Qn -fno-pic -fno-pie -fno-asynchronous-unwind-tables -mpreferred-stack-boundary=2 -fomit-frame-pointer -O0 -finput-charset=UTF-8 -fexec-charset=GB2312 -mno-mmx -mno-sse -mfpmath=387 -w -c $*.c -o $(out_path_src)$*.o
+ $(gcc) -I$(incpath_src) -nostdinc -nolibc -nostdlib -fno-builtin -ffreestanding -fno-stack-protector -Qn -fno-pic -fno-pie -fno-asynchronous-unwind-tables -mpreferred-stack-boundary=2 -fomit-frame-pointer -O0 -finput-charset=UTF-8 -fexec-charset=GB2312 -mno-mmx -mno-sse -mfpmath=387 -w -c $*.c -o $(out_path_src)$*.o
$(out_path_src)%.obj : %.asm Makefile
- nasm -f elf $*.asm -o $(out_path_src)$*.obj
+ nasm -f elf $*.asm -o $(out_path_src)$*.obj
```
### Python
@@ -269,4 +268,4 @@ if a != 0:
exit(-1)
print("Launching i386 vm...")
-```
\ No newline at end of file
+```
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/interrupt.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/interrupt.md"
index 35fe9690..bba030e6 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/interrupt.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/interrupt.md"
@@ -30,13 +30,13 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
### 异常中断
-异常中断是非可屏蔽中断, 由CPU内部触发,用于向正在运行的内核发出需要其处理的一些异常。
+异常中断是非可屏蔽中断, 由CPU内部触发,用于向正在运行的内核发出需要其处理的一些异常。
在Intel规定中,前32个中断向量被留为异常
* 在中断流程里发生异常中断叫 `Double Fault`
* 在 `Doubel Fault` 里再次发生中断叫 `Triple Fault`
-> 当发生 `Triple Fault` 类型中断时候, 计算机系统意识到发生了内核无法解决的严重错误,
+> 当发生 `Triple Fault` 类型中断时候, 计算机系统意识到发生了内核无法解决的严重错误,
> 这个时候计算机系统会越过ACPI等电源的设置迅速进行重启。
以下是一份IDT各种异常的对照表
@@ -45,14 +45,12 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
[**OSDEV Exceptions**](https://wiki.osdev.org/Exceptions) OSDEV网站有对异常中断作详细的解释
-
### 中断请求 (IRQ) 或硬件中断
这种类型的中断由芯片组在外部产生,并通过锁定到相关 CPU 的 #INTR 引脚或等效信号来发出信号。属于可屏蔽中断的一种。
> 在最初的32系统开发中, 我们会接触到一个叫做8259A的可编程中断控制器
-
### 软中断
这类中断通常由用户程序触发, 一般用于 Syscall 系统调用等功能,属于可屏蔽中断的一种
@@ -66,6 +64,7 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
> 通常, 我们建议你将这些结构体定义在头文件中, 以方便我们在其他地方复用它们
1. 中断门描述符结构体
+
```c
struct idt_entry_struct {
uint16_t base_low;
@@ -77,8 +76,9 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
typedef struct idt_entry_struct idt_entry_t;
```
-
+
2. IDT指针声明
+
```c
struct idt_ptr_struct {
uint16_t limit;
@@ -87,16 +87,18 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
typedef struct idt_ptr_struct idt_ptr_t;
```
-
+
3. 以及一些函数的预定义
+
```c
void idt_install(); //IDT初始化
void idt_use_reg(uint8_t num,uint32_t base); //注册用户程序可触发的中断, 这个在我们以后写到syscall时候要用
void idt_set_gate(uint8_t num, uint32_t base, uint16_t sel, uint8_t flags); //注册一般中断
```
-
+
4. 汇编定义的ISR处理函数
+
```c
#define DECLARE_ISR(i) extern void isr##i();
@@ -156,6 +158,7 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
```
5. 中断触发前的CPU各种寄存器状态以及中断号等
+
```c
typedef struct registers {
uint32_t ds; // 我们自己弹入的,当前数据段
@@ -167,6 +170,7 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
```
6. 方便内核注册中断处理函数以及一些其他定义
+
```c
#define IRQ0 32
#define IRQ1 33
@@ -307,6 +311,7 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
```
3. C语言中的中断预处理函数, 由汇编调用
+
```c
void isr_handler(registers_t regs) {
//printf("\n[Kernel]: received interrupt: %d\n",regs.int_no); 这里你可以输出一下异常中断号,也可以不输出
@@ -333,5 +338,4 @@ IDT有特殊的标志位规定某些中断是否可以由用户程序使用 `int
[**interrupt.asm**](/教程/示例代码/项目/mdrOS/interrupt.asm)
-
到这里, 我们内核就基本具备了对中断的处理能力, 以后编写程序驱动, 异常处理都可以通过我们已经编写好的函数去注册
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/memory.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/memory.md"
index 3de81faf..3f5ade19 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/memory.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/memory.md"
@@ -30,7 +30,6 @@
* 段界限(20位),占据描述符的第0~15位和第48~51位,前者存储低16位,后者存储高4位。
* 段属性(12位),占据描述符的第39~47位和第49~55位,段属性可以细分为8种:TYPE属性、S属性、DPL属性、P属性、AVL属性、L属性、D/B属性和G属性。
-
### 如何配置
在32位保护模式下, GDT的配置是必须的。这里我们用C配置一个简易的GDT, 方便我们后期使用分页式内存管理
@@ -58,8 +57,8 @@
uint32_t base;
} __attribute__((packed)) gdt_ptr_t;
-
- void gdt_install();
+
+ void gdt_install();
```
2. 源文件
@@ -122,7 +121,6 @@
ret ; 刷新完毕,返回
```
-
## 分页式内存管理
在分页系统下,一个程序发出的虚拟地址由两部分组成: 页面号和页内偏移值。
@@ -152,7 +150,6 @@ MMU依赖于页表来进行一切与页面有关的管理活动,这些活动
> 页框不止可以以4kb为大小, 你也可以设置为4MB、1GB等大小。但是那样的页太大了,一般用于64位更大的内存上管理
-
由于C代码对于内存管理整个模块的耦合性较高, 无法单独将代码片段完整展示出来。故列出了所有的源文件
* [**kheap.c**](/教程/示例代码/项目/mdrOS/kheap.c) 内核堆实现
@@ -160,7 +157,7 @@ MMU依赖于页表来进行一切与页面有关的管理活动,这些活动
* [**memory.h**](/教程/示例代码/项目/mdrOS/memory.h) 各种结构的预定义
* [**memory.c**](/教程/示例代码/项目/mdrOS/memory.c) 常用内存操作函数
-> 其中可以删除有关task的代码, 该代码是多进程的一部分实现。我们没进行到多进程那一步可以先不用,
+> 其中可以删除有关task的代码, 该代码是多进程的一部分实现。我们没进行到多进程那一步可以先不用,
> 现在首要任务是确保我们所写的分页式内存管理可用
## 堆内存管理
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/video_driver.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/video_driver.md"
index a1577702..736b142e 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/video_driver.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/video_driver.md"
@@ -11,6 +11,7 @@
其显存基址为 `0xB8000`
> 注意: UEFI引导方式不存在这块区域, UEFI的显存区域由`BootService`提供给你
+>
### 编写VGA视频驱动程序
1. 准备工作
@@ -26,12 +27,13 @@
asm volatile("outb %b0, %w1" : : "a"(data), "Nd"(port));
}
```
-
+
* 关于`0xB8000`: 在OS代码中一般用16进制表示一些内存地址, 这样代码展现比较直观好辨认, 相比十进制或者二进制, 代码长度也会有所缩减
- [关于进制的知识](/教程/番外/77_关于进制.md)
-
+ [关于进制的知识](/教程/番外/77_关于进制.md)
+
2. 实现滚屏 光标位置设置
+
```c
static void scroll() { //滚屏代码实现
uint8_t attributeByte = (0 << 4) | (15 & 0x0F);
@@ -102,15 +104,13 @@
}
```
-> 什么? 你问我printf函数怎么实现?
+> 什么? 你问我printf函数怎么实现?
> 别着急, 请看下面
[MdrOS的printf函数实现](/教程/示例代码/项目/mdrOS/printf.c)
-
-
## VBE (VESA BIOS EXTENSION) VESA BIOS扩展
-> SVGA (Super VGA) \
+> **SVGA (Super VGA)** \
> IBM的VGA标准是显示卡发展史上的一块丰碑。
> 但后来无法满足人们的需要,于是市场上出现了TVGA、S3系列、
> Cirrus Logic、ET等为首的一批显示卡,提供了比VGA分辨率更高,颜色更丰富的显示模式,
@@ -126,10 +126,10 @@
## 如何开启VBE模式
> 操作系统开发前期我们不是很建议您使用VBE模式,
-以LegacyBIOS为例,我们刚进入引导一般都是VGA模式,这种显示模式的功能非常有限,只能打印字符和少许的颜色
+以LegacyBIOS为例,我们刚进入引导一般都是VGA模式,这种显示模式的功能非常有限,只能打印字符和少许的颜色
而进入VBE高分辨率显示模式,我们可以自由绘画图形, 可以显示的颜色升级为RGB
1. 在16位实模式中开启VBE显示模式
```c
- ```
\ No newline at end of file
+ ```
diff --git "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/\351\241\271\347\233\256\346\246\202\350\277\260.md" "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/\351\241\271\347\233\256\346\246\202\350\277\260.md"
index 99e7281f..064d151c 100644
--- "a/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/\351\241\271\347\233\256\346\246\202\350\277\260.md"
+++ "b/\346\225\231\347\250\213/\346\255\243\346\226\207/\351\241\271\347\233\256/MdrOS/\351\241\271\347\233\256\346\246\202\350\277\260.md"
@@ -5,15 +5,15 @@
## 概念
-
操作系统是一种系统软件,它是控制管理计算机系统的硬软件,分配调度资源的管理者
-其内部功能有:
+操作系统是一种系统软件,它是控制管理计算机系统的硬软件,分配调度资源的管理者 +其内部功能有: * 内存管理 * 设备驱动 * 中断处理 * 任务调度 -#### 计算机启动过程 +### 计算机启动过程 1. 电源键按下 2. POST加电硬件自检 @@ -26,10 +26,12 @@ ## 环境准备 您需要: + * [i686-elf-tools](https://github.com/lordmilko/i686-elf-tools/releases/tag/13.2.0) 交叉编译工具链 * [nasm](https://nasm.us/) 汇编编译器 以及(选择性): + * [Python3](https://www.python.org/downloads/) 充当构建脚本 * [Makefile](https://www.gnu.org/software/make/) 充当构建脚本 @@ -69,4 +71,4 @@ * 64位长的操作系统会比32位保护模式的操作系统实现更难, 比如32位只需要二级页表即可,64位需要4级甚至更多才能管理所有内存 * ARM等其他架构的CPU与x86平台的CPU实现截然不同, 其中x86的很多机制在ARM是没有的, 同理ARM某些机制x86也没有 * 本教程只是教学您如何实现一个最简单的宏内核操作系统,如果您想完善您的操作系统, 可以去查阅更多的资料 -* 操作系统编写好都是要在实体机上测试的, 无法在实体机上跑的操作系统就不是一个真正的操作系统 \ No newline at end of file +* 操作系统编写好都是要在实体机上测试的, 无法在实体机上跑的操作系统就不是一个真正的操作系统 diff --git "a/\346\225\231\347\250\213/\347\225\252\345\244\226/77_\345\205\263\344\272\216\350\277\233\345\210\266.md" "b/\346\225\231\347\250\213/\347\225\252\345\244\226/77_\345\205\263\344\272\216\350\277\233\345\210\266.md" index 2ba74ce0..d19b58c4 100644 --- "a/\346\225\231\347\250\213/\347\225\252\345\244\226/77_\345\205\263\344\272\216\350\277\233\345\210\266.md" +++ "b/\346\225\231\347\250\213/\347\225\252\345\244\226/77_\345\205\263\344\272\216\350\277\233\345\210\266.md" @@ -3,14 +3,17 @@ ## 1. 什么是进制 我们通常都是基于数字10来表示数字,比如2157,千位为2、百位为1、十位为5、个位为7,由此,我们可以得出一个等式 + ```C 2157 == 2 * 10^3 + 1 * 10^2 + 5 * 10^1 + 7 * 10^0 ``` + 因为这种方法是基于10的幂,所以称以10为基底书写2157 姑且认为这种书写方法是得益于我们有10根手指。从某种意义上看,计算机只有2根手指,只能表示0和1,因此,计算机适用于基底为2的数制系统。 它使用2的幂而不是10的幂。以2为基底表示的数统称为 **二进制数** ( _binary number_ ), 二进制中的2和十进制中的10作用一样,都是基数,而2的幂则相当于十进制中的10的幂。例如: + ```C 1011 == 1 * 2^3 + 0 * 2^2 + 1 * 2^1 + 1 * 2^0 ``` @@ -22,12 +25,15 @@ ### 1.1 **二进制** 二进制字面量以 `0b` 或 `0B` 开头,后面跟着二进制数字(0 和 1)。例如: + ```C int binary = 0b1010; // 二进制 1010,十进制 10 ``` + ### 1.2 **八进制** 八进制字面量以 `0` 开头,后面跟着八进制数字(0-7)。例如: + ```C int octal = 012; // 八进制 12,十进制 10 ``` @@ -35,7 +41,7 @@ int octal = 012; // 八进制 12,十进制 10 每个八进制位都对应一个 **3** 位二进制数 ( 即 **3** 个二进制位 ), 下图列出了八进制和二进制之间的对应关系: -> **注意**:转换的时候不能省略中间的 `0` +> **注意**:转换的时候不能省略中间的 `0` | 十进制 | 八进制 | 对应二进制 | |-------|-------|-------| @@ -53,6 +59,7 @@ int octal = 012; // 八进制 12,十进制 10 ### 1.3 **十进制** 十进制字面量是默认的表示方法,不需要前缀。例如: + ```C int decimal = 10; // 十进制 10 ``` @@ -63,6 +70,7 @@ int decimal = 10; // 十进制 10 所以我们用字母 `A ~ F` ( `a ~ f` )来表示。 十六进制字面量以 `0x` 或 `0X` 开头,后面跟着十六进制数字(0-9 和 a-f 或 A-F)。例如: + ```C int hexadecimal = 0xA; // 十六进制 A,十进制 10 ``` diff --git "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/linkfix.py" "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/linkfix.py" index bdf8d857..b77cdfa1 100644 --- "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/linkfix.py" +++ "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/linkfix.py" @@ -1,8 +1,9 @@ # coding=utf-8 from os import walk from os.path import join -for path, _, files in walk('.'): + +for path, _, files in walk("."): for file in files: - if not file.endswith('.md'): - with open(join(path, file) + '.md', 'w') as f: - f.write(f"# {file}\n\n[{file}](./{file} ':include')\n") \ No newline at end of file + if not file.endswith(".md"): + with open(join(path, file) + ".md", "w") as f: + f.write(f"# {file}\n\n[{file}](./{file} ':include')\n") diff --git "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210_\346\225\260\347\273\204_1.h" "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210_\346\225\260\347\273\204_1.h" index 2d8da840..5ce56857 100644 --- "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210_\346\225\260\347\273\204_1.h" +++ "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\346\240\210_\346\225\260\347\273\204_1.h" @@ -15,41 +15,50 @@ typedef struct int top; } Stack; -void initStack(Stack* s) +void initStack(Stack *s) { s->top = -1; - for (int i = 0; i < cap; i++) { + for (int i = 0; i < cap; i++) + { s->array[i] = 0; } } -void push(Stack* s, ElementType e) +void push(Stack *s, ElementType e) { - if (s->top == cap - 1) { + if (s->top == cap - 1) + { printf("Stack Overflow\n"); - } else { + } + else + { s->array[++s->top] = e; } } -ElementType pop(Stack* s) +ElementType pop(Stack *s) { - if (s->top == -1) { + if (s->top == -1) + { printf("Stack Underflow\n"); return 0; } return s->array[s->top--]; } -void printStack(const Stack* s) +void printStack(const Stack *s) { printf("%d element", s->top + 1); - if (s->top == -1 || s->top == 0) { + if (s->top == -1 || s->top == 0) + { printf(": [ "); - } else { + } + else + { printf("s: [ "); } - for (int i = 0; i <= s->top; i++) { + for (int i = 0; i <= s->top; i++) + { printf("%d ", s->array[i]); } printf("]\n"); diff --git "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\241\272\345\272\217\350\241\250.h" "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\241\272\345\272\217\350\241\250.h" index b6d26511..984856bc 100644 --- "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\241\272\345\272\217\350\241\250.h" +++ "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\346\225\260\346\215\256\347\273\223\346\236\204/\351\241\272\345\272\217\350\241\250.h" @@ -12,16 +12,18 @@ constexpr int g_initCap = 4; typedef int ElementType; -typedef struct { - ElementType* arr; - size_t size; // length of the sequence list +typedef struct +{ + ElementType *arr; + size_t size; // length of the sequence list size_t capacity; // size of the array } SeqList; -void initSeqList(SeqList* l) +void initSeqList(SeqList *l) { - l->arr = (ElementType*)malloc(sizeof(ElementType) * g_initCap); - if (!(l->arr)) { + l->arr = (ElementType *)malloc(sizeof(ElementType) * g_initCap); + if (!(l->arr)) + { printf("Initialization failed!\n"); exit(-1); } @@ -29,44 +31,48 @@ void initSeqList(SeqList* l) l->capacity = g_initCap; } -void initSeqListFromArray(SeqList* l, const ElementType* a, int length) +void initSeqListFromArray(SeqList *l, const ElementType *a, int length) { - l->arr = (ElementType*)malloc(sizeof(ElementType) * length); - if (!(l->arr)) { + l->arr = (ElementType *)malloc(sizeof(ElementType) * length); + if (!(l->arr)) + { printf("Initialization failed!\n"); exit(-1); } - for (size_t n = 0; n < length; ++n) { + for (size_t n = 0; n < length; ++n) + { l->arr[n] = a[n]; } l->size = length; l->capacity = length; } -void clearSeqList(SeqList* l) +void clearSeqList(SeqList *l) { free(l->arr); initSeqList(l); } -bool isSeqListEmpty(const SeqList* l) { return l->size == 0; } +bool isSeqListEmpty(const SeqList *l) { return l->size == 0; } -size_t lengthOfSeqList(const SeqList* l) { return l->size; } +size_t lengthOfSeqList(const SeqList *l) { return l->size; } -ElementType getFromSeqList(const SeqList* l, int i) +ElementType getFromSeqList(const SeqList *l, int i) { - if (i >= l->size) { + if (i >= l->size) + { printf("Index out of bound!\n"); return 0; } return l->arr[i]; } -void expandSeqList(SeqList* l) +void expandSeqList(SeqList *l) { printf("Expansion\n"); - ElementType* newArr = (ElementType*)realloc(l->arr, sizeof(ElementType) * 2 * l->capacity); - if (!(newArr)) { + ElementType *newArr = (ElementType *)realloc(l->arr, sizeof(ElementType) * 2 * l->capacity); + if (!(newArr)) + { printf("Expansion failed!\n"); exit(-1); } @@ -74,11 +80,12 @@ void expandSeqList(SeqList* l) l->arr = newArr; } -void curtailSeqList(SeqList* l) +void curtailSeqList(SeqList *l) { printf("Curtailment\n"); - ElementType* newArr = (ElementType*)realloc(l->arr, sizeof(ElementType) * l->capacity / 2); - if (!newArr) { + ElementType *newArr = (ElementType *)realloc(l->arr, sizeof(ElementType) * l->capacity / 2); + if (!newArr) + { printf("Curtailment failed!\n"); exit(-1); } @@ -86,54 +93,62 @@ void curtailSeqList(SeqList* l) l->arr = newArr; } -void insertBack2SeqList(SeqList* l, ElementType x) +void insertBack2SeqList(SeqList *l, ElementType x) { - if (l->size == l->capacity) { + if (l->size == l->capacity) + { expandSeqList(l); } l->arr[l->size] = x; l->size += 1; } -void insert2SeqList(SeqList* l, int i, ElementType x) +void insert2SeqList(SeqList *l, int i, ElementType x) { - if (l->size == l->capacity) { + if (l->size == l->capacity) + { expandSeqList(l); } - for (size_t n = l->size; n > i; --n) { + for (size_t n = l->size; n > i; --n) + { l->arr[n] = l->arr[n - 1]; } l->arr[i] = x; l->size += 1; } -void removeFromSeqList(SeqList* l, int i) +void removeFromSeqList(SeqList *l, int i) { if (i >= l->size) printf("Index out of bound!\n"); - for (size_t n = i; n < l->size - 1; ++n) { + for (size_t n = i; n < l->size - 1; ++n) + { l->arr[n] = l->arr[n + 1]; } l->size -= 1; - if ((l->size + 1) * 4 < l->capacity) { + if ((l->size + 1) * 4 < l->capacity) + { curtailSeqList(l); } } -int indexOfSeqList(const SeqList* l, ElementType x) +int indexOfSeqList(const SeqList *l, ElementType x) { - for (int n = 0; n < l->size; ++n) { - if (l->arr[n] == x) { + for (int n = 0; n < l->size; ++n) + { + if (l->arr[n] == x) + { return n; } } return -1; } -void printSeqList(const SeqList* l) +void printSeqList(const SeqList *l) { printf("cap: %zu size: %zu ==>", l->capacity, l->size); - for (size_t i = 0; i < l->size; ++i) { + for (size_t i = 0; i < l->size; ++i) + { printf(" [%zu]=%d", i, l->arr[i]); } printf("\n"); diff --git "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/4_\345\210\206\346\262\273\346\263\225/4_1_\345\275\222\345\271\266\346\216\222\345\272\217.c" "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/4_\345\210\206\346\262\273\346\263\225/4_1_\345\275\222\345\271\266\346\216\222\345\272\217.c" index f6a5c10b..70217e90 100644 --- "a/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/4_\345\210\206\346\262\273\346\263\225/4_1_\345\275\222\345\271\266\346\216\222\345\272\217.c" +++ "b/\346\225\231\347\250\213/\347\244\272\344\276\213\344\273\243\347\240\201/\346\225\260\346\215\256\347\273\223\346\236\204\344\270\216\347\256\227\346\263\225/\347\256\227\346\263\225/4_\345\210\206\346\262\273\346\263\225/4_1_\345\275\222\345\271\266\346\216\222\345\272\217.c" @@ -5,19 +5,21 @@ #include