diff --git a/404.html b/404.html index a7be918..408d583 100644 --- a/404.html +++ b/404.html @@ -18,7 +18,7 @@
- + \ No newline at end of file diff --git a/assets/5.BzSkS-4w.svg b/assets/5.BzSkS-4w.svg new file mode 100644 index 0000000..bf21197 --- /dev/null +++ b/assets/5.BzSkS-4w.svg @@ -0,0 +1,4 @@ + + + +
程序
内存条
00000000
00000000
00000000
00001010
内存地址
存储单元
0x7ffc3e5cc514
0x7ffc3e5cc515
0x7ffc3e5cc516
0x7ffc3e5cc517
num(变量)
内存地址:0x7ffc3e5cc514
10 的二进制
\ No newline at end of file diff --git a/assets/5.DLoOQY6Z.svg b/assets/5.DLoOQY6Z.svg deleted file mode 100644 index 292df67..0000000 --- a/assets/5.DLoOQY6Z.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
程序
内存条
00000000
00000000
00000000
00001010
内存地址
存储单元
0x7ffc3e5cc514
0x7ffc3e5cc515
0x7ffc3e5cc516
0x7ffc3e5cc517
num(变量)
内存地址:0x7ffc3e5cc514
10 的二进制
\ No newline at end of file diff --git a/assets/6.BLsIqs5q.svg b/assets/6.BLsIqs5q.svg deleted file mode 100644 index f0230d0..0000000 --- a/assets/6.BLsIqs5q.svg +++ /dev/null @@ -1,4 +0,0 @@ - - - -
程序
内存条
00000000
00000000
00000000
00001010
内存地址
存储单元
0x7ffc3e5cc514
0x7ffc3e5cc515
0x7ffc3e5cc516
0x7ffc3e5cc517
num(变量)
内存地址:0x7ffc3e5cc514
10 的二进制
p(变量)
内存地址:0x7ffd7b5bdcb0
00000000
00000000
01111111
11111100
00111110
01011100
11000101
00010100
0x7ffd7b5bdcb0
0x7ffd7b5bdcb1
0x7ffd7b5bdcb2
0x7ffd7b5bdcb3
0x7ffd7b5bdcb4
0x7ffd7b5bdcb5
0x7ffd7b5bdcb6
0x7ffd7b5bdcb7
内存地址
存储单元
0x7ffc3e5cc514 的二进制
\ No newline at end of file diff --git a/assets/6.BPY9ZGed.svg b/assets/6.BPY9ZGed.svg new file mode 100644 index 0000000..38ada02 --- /dev/null +++ b/assets/6.BPY9ZGed.svg @@ -0,0 +1,4 @@ + + + +
程序
内存条
00000000
00000000
00000000
00001010
内存地址
存储单元
0x7ffc3e5cc514
0x7ffc3e5cc515
0x7ffc3e5cc516
0x7ffc3e5cc517
num(变量)
内存地址:0x7ffc3e5cc514
10 的二进制
p(变量)
内存地址:0x7ffd7b5bdcb0
00000000
00000000
01111111
11111100
00111110
01011100
11000101
00010100
0x7ffd7b5bdcb0
0x7ffd7b5bdcb1
0x7ffd7b5bdcb2
0x7ffd7b5bdcb3
0x7ffd7b5bdcb4
0x7ffd7b5bdcb5
0x7ffd7b5bdcb6
0x7ffd7b5bdcb7
内存地址
存储单元
0x7ffc3e5cc514 的二进制
\ No newline at end of file diff --git a/assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.js b/assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.js similarity index 99% rename from assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.js rename to assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.js index 7bcd59a..911958a 100644 --- a/assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.js +++ b/assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.js @@ -1,4 +1,4 @@ -import{_ as s,c as i,o as a,a6 as n}from"./chunks/framework.CZRoMP2i.js";const t="/c/assets/1.L8V3GBrc.png",l="/c/assets/2.CdvhiwcU.png",e="/c/assets/3.D74t3-Xt.png",d="/c/assets/4.DqDR6Thp.svg",p="/c/assets/5.DLoOQY6Z.svg",h="/c/assets/6.BLsIqs5q.svg",C=JSON.parse('{"title":"第一章:颇具争议的指针","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/06_xdx/index.md","filePath":"notes/01_c-basic/06_xdx/index.md","lastUpdated":1723342978000}'),r={name:"notes/01_c-basic/06_xdx/index.md"},k=n('

第一章:颇具争议的指针

1.1 概述

NOTE

之所以指针在 C 语言中颇具争议,是因为一方面其功能强大,直接操作内存地址;另一方面,又很危险,不正确的使用指针的方式,非常容易导致程序崩溃。

IMPORTANT

1.2 现代化高级编程语言是如何解决指针危险的?

IMPORTANT

总而言之,各种编程语言通过引入不同的策略和机制,如:智能指针、垃圾回收器、所有权和借用,以及强类型系统,有效地减少了指针操作所带来的各种安全性和可靠性问题,提升了程序的稳定性和开发效率。

第二章:回顾知识

2.1 变量

c
数据类型 变量名 = 值 ;

IMPORTANT

变量名(标识符)需要符合命名规则和命名规范!!!

2.2 普通变量和指针变量的区别

img

2.3 运算符

2.3.1 概述

img

NOTE

掌握一个运算符,需要关注以下几个方面:

IMPORTANT

普通变量支持上述的所有运算符;而指针变量并非支持上述的所有运算符,且支持运算符的含义和普通变量相差较大!!!

2.3.2 运算符的优先级

优先级运算符名称或含义结合方向
1[]数组下标➡️(从左到右)
()圆括号
.成员选择(对象)
->成员选择(指针)
2-负号运算符⬅️(从右到左)
(类型)强制类型转换
++自增运算符
--自减运算符
*取值运算符
&取地址运算符
!逻辑非运算符
~按位取反运算符
sizeof长度运算符
3/➡️(从左到右)
*
%余数(取模)
4+➡️(从左到右)
-
5<<左移➡️(从左到右)
>>右移
6>大于➡️(从左到右)
>=大于等于
<小于
<=小于等于
7==等于➡️(从左到右)
!=不等于
8&按位与➡️(从左到右)
9^按位异或➡️(从左到右)
10|按位或➡️(从左到右)
11&&逻辑与➡️(从左到右)
12||逻辑或➡️(从左到右)
13?:条件运算符⬅️(从右到左)
14=赋值运算符⬅️(从右到左)
/=除后赋值
*=乘后赋值
%=取模后赋值
+=加后赋值
-=减后赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
^=按位异或后赋值
|=按位或后赋值
15,逗号运算符➡️(从左到右)

WARNING

IMPORTANT

第三章:指针的理解和定义(⭐)

3.1 变量的访问方式

c
#include <stdio.h>
+import{_ as s,c as i,o as a,a6 as n}from"./chunks/framework.CZRoMP2i.js";const t="/c/assets/1.L8V3GBrc.png",l="/c/assets/2.CdvhiwcU.png",e="/c/assets/3.D74t3-Xt.png",d="/c/assets/4.DqDR6Thp.svg",p="/c/assets/5.BzSkS-4w.svg",h="/c/assets/6.BPY9ZGed.svg",C=JSON.parse('{"title":"第一章:颇具争议的指针","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/06_xdx/index.md","filePath":"notes/01_c-basic/06_xdx/index.md","lastUpdated":1723342978000}'),r={name:"notes/01_c-basic/06_xdx/index.md"},k=n('
  • 指针是 C 语言中最重要的概念之一,也是最难以理解的概念之一。
  • 指针是 C 语言的精髓,要想掌握 C 语言就需要深入地了解指针。

第一章:颇具争议的指针

1.1 概述

  • 目前而言,操作系统几乎都是通过 C 语言来编写和维护的;而 C 语言提供了指针的用法,其能直接操作内存地址,是个非常强大灵活的工具;但是,需要开发者小心谨慎的使用,以确保程序的稳定性和安全性。

NOTE

之所以指针在 C 语言中颇具争议,是因为一方面其功能强大,直接操作内存地址;另一方面,又很危险,不正确的使用指针的方式,非常容易导致程序崩溃。

  • 如果没有能很好的使用指针,就会带来一系列的问题,如:

    • 空指针引用(Null Pointer Dereference):当一个指针没有正确初始化或者被赋予了空(NULL)值时,如果程序尝试访问该指针所指向的内存,会导致运行时错误,甚至导致程序崩溃。
    • 野指针(Dangling Pointers):指针指向的内存地址曾经分配给某个变量或对象,但后来该变量或对象被释放或者移动,导致指针仍指向已经无效的内存位置。对野指针进行操作可能会导致未定义的行为或程序崩溃。
    • 指针算术错误:在进行指针运算时,如果没有正确管理指针的偏移量或者超出了数组的边界,可能会导致指针指向错误的内存位置,从而影响程序的正确性和安全性。
    • 内存泄漏:如果动态分配的内存通过指针分配,但在不再需要时没有正确释放,会导致内存泄漏,长时间运行的程序可能会耗尽系统资源。
  • 为了减少指针带来的风险,开发人员可以采取以下的措施:

    • 良好的编程实践:确保指针的初始化和使用是安全的,避免空指针引用和野指针问题。
    • 边界检查:在进行指针运算时,始终确保不会超出数组或内存分配的边界。
    • 使用指针和引用的适当性:在可能的情况下,可以考虑使用更安全的语言特性,如:引用(在 C++ 等编程语言中)或者更高级别的数据结构来代替裸指针,从而减少指针使用时的潜在风险。

IMPORTANT

  • ① 既然指针很危险,那么通过一系列的手段将指针包装或屏蔽,以达到程序安全的目的(这是现代化的高级编程语言解决的思路,如:Java、Go、Rust 等)。
  • ② 之所以,指针还需要学习,是因为在嵌入式等领域,其机器的资源(CPU、内存等)非常有限;而现代化的高级编程语言虽然安全,但是需要的系统资源也庞大。
  • ③ 我们知道,编译型的程序不管编译过程如何复杂,至少需要两步:编译和运行。通常,我们也将这两步称为编译期和运行期。C 语言中的指针之所以危险就在于程序要在运行的时候才会发现问题(后知后觉);而现代化的高级编程语言中的编译器在程序编译的时候就会发现问题(提前发现问题)。
  • ④ C 语言的编译器之所以这么设计的原因,就在于当时的内存和 CPU 是非常有限(PDP-7 早期小型计算机,CPU:18 bit 的电子管逻辑,内存:4kb )和昂贵(72,000 $),如果加入安全限制的功能,会远远超过整个系统的资源。

1.2 现代化高级编程语言是如何解决指针危险的?

  • C++采用了如下的策略和机制,来解决指针危险操作的:

    • 智能指针: C++ 引入了智能指针(如std::shared_ptrstd::unique_ptr),这些指针提供了自动资源管理和所有权的语义。std::unique_ptr确保只有一个指针可以访问给定的资源,从而避免了传统指针的悬空引用和内存泄漏问题。std::shared_ptr允许多个指针共享一个资源,并在所有引用释放后自动释放。
    • 引用: C++ 中的引用(如:&符号)提供了更安全的间接访问方法,与指针相比,引用不能重新绑定到不同的对象,从而减少了意外的指针错误。
  • Go采用了如下的策略和机制,来解决指针危险操作的:

    • 内存管理和垃圾回收: Go 语言通过自动垃圾回收器管理内存,减少了手动内存管理所带来的指针操作错误。Go 的垃圾回收器定期扫描并释放不再使用的内存,避免了内存泄漏和悬空指针问题。
    • 指针的安全性: Go 语言的指针是受限的,不支持指针运算,从而减少了指针操作可能带来的风险。
  • Rust采用了如下的策略和机制,来解决指针危险操作的:

    • 所有权和借用: Rust 引入了所有权和借用的概念,编译器在编译时静态分析所有权转移和引用的生命周期。这种机制避免了数据竞争和空指针解引用等运行时错误,使得在编译时就能够保证内存安全。
    • 生命周期: Rust 的生命周期系统确保引用的有效性和安全性,防止了悬空引用和指针乱用。
  • Java采用了如下的策略和机制,来解决指针危险操作的:

    • 引用类型和自动内存管理: Java 中所有的对象引用都是通过引用来访问的,而不是直接的指针。Java 的自动垃圾回收器负责管理内存,从而避免了手动内存管理可能导致的指针错误,如:内存泄漏和悬空指针。
    • 强类型系统和异常处理: Java 的强类型系统和异常处理机制减少了指针操作带来的风险,如:空指针解引用异常(NullPointerException)。编译器在编译时能够捕获许多潜在的类型错误,进一步增强了程序的安全性和可靠性。

IMPORTANT

总而言之,各种编程语言通过引入不同的策略和机制,如:智能指针、垃圾回收器、所有权和借用,以及强类型系统,有效地减少了指针操作所带来的各种安全性和可靠性问题,提升了程序的稳定性和开发效率。

第二章:回顾知识

2.1 变量

  • 变量就是保存程序运行过程中临时产生的值,其语法如下:
c
数据类型 变量名 = 值 ;

IMPORTANT

变量名(标识符)需要符合命名规则和命名规范!!!

  • 强制规范:
    • ① 只能由小写大写英文字母0-9_ 组成。
    • ② 不能以数字开头。
    • ③ 不可以是关键字
    • ④ 标识符具有长度限制,不同编译器和平台会有所不同,一般限制在 63 个字符内。
    • ⑤ 严格区分大小写字母,如:Hello、hello 是不同的标识符。
  • 建议规范:
    • ① 为了提高阅读性,使用有意义的单词,见名知意,如:sum,name,max,year 等。
    • ② 使用下划线连接多个单词组成的标识符,如:max_classes_per_student 等。
    • ③ 多个单词组成的标识符,除了使用下划线连接,也可以使用小驼峰命名法,除第一个单词外,后续单词的首字母大写,如: studentId、student_name 等。
    • ④ 不要出现仅靠大小写区分不同的标识符,如:name、Name 容易混淆。
    • ⑤ 系统内部使用了一些下划线开头的标识符,如:C99 标准添加的类型 _Bool,为防止冲突,建议开发者尽量避免使用下划线开头的标识符。
  • 变量名作用,如下所示:
    • ① 当我们编写代码的时候,使用变量名关联某块内存的地址
    • ② 当 CPU 执行的时候,会将变量名替换为具体的地址,再进行具体的操作。

2.2 普通变量和指针变量的区别

  • 根据变量存储不同,我们可以将变量分为两类:
    • 普通变量:变量所对应的内存中存储的是普通值
    • 指针变量:变量所对应的内存中存储的是另一个变量的地址
  • 如下图所示:

img

  • 普通变量和指针变量的相同点,如下所示:
    • ① 普通变量有内存空间,指针变量也有内存空间。
    • ② 普通变量有内存地址,指针变量也有内存地址。
    • ③ 普通变量所对应的内存空间中有值,指针变量所对应的内存空间中也有值。
  • 普通变量和指针变量的不同点:
    • 普通变量所对应的内存空间存储的是普通的值,如:整数、小数、字符等;指针变量所对应的内存空间存储的是另外一个变量的地址
    • 普通变量有普通变量的运算方式,而指针变量有指针变量的运算方式(后续讲解)。

2.3 运算符

2.3.1 概述

  • 运算符是一种特殊的符号,用于数据的运算、赋值和比较等。
  • 表达式指的是一组运算数、运算符的组合,表达式一定具有值,一个变量或一个常量可以是表达式,变量、常量和运算符也可以组成表达式,如:

img

  • 操作数指的是参与运算或者对象,如:

  • 根据操作数个数,可以将运算符分为:
    • 一元运算符(一目运算符)。
    • 二元运算符(二目运算符)。
    • 三元运算符(三目运算符)。
  • 根据功能,可以将运算符分为:
    • 算术运算符。
    • 关系运算符(比较运算符)。
    • 逻辑运算符。
    • 赋值运算符。
    • 逻辑运算符。
    • 位运算符。
    • 三元运算符。

NOTE

掌握一个运算符,需要关注以下几个方面:

  • ① 运算符的含义。
  • ② 运算符操作数的个数。
  • ③ 运算符所组成的表达式。
  • ④ 运算符有无副作用,即:运算后是否会修改操作数的值。

IMPORTANT

普通变量支持上述的所有运算符;而指针变量并非支持上述的所有运算符,且支持运算符的含义和普通变量相差较大!!!

2.3.2 运算符的优先级

  • C 语言中运算符的优先级,如下所示:
优先级运算符名称或含义结合方向
1[]数组下标➡️(从左到右)
()圆括号
.成员选择(对象)
->成员选择(指针)
2-负号运算符⬅️(从右到左)
(类型)强制类型转换
++自增运算符
--自减运算符
*取值运算符
&取地址运算符
!逻辑非运算符
~按位取反运算符
sizeof长度运算符
3/➡️(从左到右)
*
%余数(取模)
4+➡️(从左到右)
-
5<<左移➡️(从左到右)
>>右移
6>大于➡️(从左到右)
>=大于等于
<小于
<=小于等于
7==等于➡️(从左到右)
!=不等于
8&按位与➡️(从左到右)
9^按位异或➡️(从左到右)
10|按位或➡️(从左到右)
11&&逻辑与➡️(从左到右)
12||逻辑或➡️(从左到右)
13?:条件运算符⬅️(从右到左)
14=赋值运算符⬅️(从右到左)
/=除后赋值
*=乘后赋值
%=取模后赋值
+=加后赋值
-=减后赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
^=按位异或后赋值
|=按位或后赋值
15,逗号运算符➡️(从左到右)

WARNING

  • ① 不要过多的依赖运算符的优先级来控制表达式的执行顺序,这样可读性太差,尽量使用小括号来控制表达式的执行顺序。
  • ② 不要把一个表达式写得过于复杂,如果一个表达式过于复杂,则把它分成几步来完成。
  • ③ 运算符优先级不用刻意地去记忆,总体上:一元运算符 > 算术运算符 > 关系运算符 > 逻辑运算符 > 三元运算符 > 赋值运算符。

IMPORTANT

  • ① 取值运算符 * 和取地址运算符 & 的优先级相同,并且运算方向都是从右向左!!!
  • ② 逗号运算符 , 的优先级最低,并且运算方向是从左向右!!!

第三章:指针的理解和定义(⭐)

3.1 变量的访问方式

  • 计算机中程序的运行都是在内存中进行的,变量也是内存中分配的空间,且不同类型的变量占据的内存空间大小不同,如:char 类型的变量是 1 个字节,short 类型的变量是 2 个字节,int 类型的变量是 4 个字节...
  • 之前我们都是通过变量名(普通变量)访问内存中存储的数据,如下所示:
c
#include <stdio.h>
 
 int main() {
 
diff --git a/assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.lean.js b/assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.lean.js
similarity index 90%
rename from assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.lean.js
rename to assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.lean.js
index 7e4769e..6ecfcd5 100644
--- a/assets/notes_01_c-basic_06_xdx_index.md.DRqcekTM.lean.js
+++ b/assets/notes_01_c-basic_06_xdx_index.md.Cx7CzRES.lean.js
@@ -1 +1 @@
-import{_ as s,c as i,o as a,a6 as n}from"./chunks/framework.CZRoMP2i.js";const t="/c/assets/1.L8V3GBrc.png",l="/c/assets/2.CdvhiwcU.png",e="/c/assets/3.D74t3-Xt.png",d="/c/assets/4.DqDR6Thp.svg",p="/c/assets/5.DLoOQY6Z.svg",h="/c/assets/6.BLsIqs5q.svg",C=JSON.parse('{"title":"第一章:颇具争议的指针","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/06_xdx/index.md","filePath":"notes/01_c-basic/06_xdx/index.md","lastUpdated":1723342978000}'),r={name:"notes/01_c-basic/06_xdx/index.md"},k=n("",87),o=[k];function c(g,E,u,b,y,F){return a(),i("div",null,o)}const A=s(r,[["render",c]]);export{C as __pageData,A as default};
+import{_ as s,c as i,o as a,a6 as n}from"./chunks/framework.CZRoMP2i.js";const t="/c/assets/1.L8V3GBrc.png",l="/c/assets/2.CdvhiwcU.png",e="/c/assets/3.D74t3-Xt.png",d="/c/assets/4.DqDR6Thp.svg",p="/c/assets/5.BzSkS-4w.svg",h="/c/assets/6.BPY9ZGed.svg",C=JSON.parse('{"title":"第一章:颇具争议的指针","description":"","frontmatter":{},"headers":[],"relativePath":"notes/01_c-basic/06_xdx/index.md","filePath":"notes/01_c-basic/06_xdx/index.md","lastUpdated":1723342978000}'),r={name:"notes/01_c-basic/06_xdx/index.md"},k=n("",87),o=[k];function c(g,E,u,b,y,F){return a(),i("div",null,o)}const A=s(r,[["render",c]]);export{C as __pageData,A as default};
diff --git a/hashmap.json b/hashmap.json
index 0af5e34..5736349 100644
--- a/hashmap.json
+++ b/hashmap.json
@@ -1 +1 @@
-{"index.md":"n0W-Fd-u","notes_01_c-basic_00_xdx_index.md":"D2tOvV0j","notes_01_c-basic_01_xdx_index.md":"DynzO91I","notes_01_c-basic_02_xdx_index.md":"BomW9C52","notes_01_c-basic_03_xdx_index.md":"lC6l29W7","notes_01_c-basic_04_xdx_index.md":"DkXfRsso","notes_01_c-basic_05_xdx_index.md":"Dzk0jyse","notes_01_c-basic_06_xdx_index.md":"DRqcekTM","notes_04_linux_01_xdx_index.md":"D7-UlHSH","notes_index.md":"bgNns6d1"}
+{"index.md":"n0W-Fd-u","notes_01_c-basic_00_xdx_index.md":"D2tOvV0j","notes_01_c-basic_01_xdx_index.md":"DynzO91I","notes_01_c-basic_02_xdx_index.md":"BomW9C52","notes_01_c-basic_03_xdx_index.md":"lC6l29W7","notes_01_c-basic_04_xdx_index.md":"DkXfRsso","notes_01_c-basic_05_xdx_index.md":"Dzk0jyse","notes_01_c-basic_06_xdx_index.md":"Cx7CzRES","notes_04_linux_01_xdx_index.md":"D7-UlHSH","notes_index.md":"bgNns6d1"}
diff --git a/index.html b/index.html
index 0aee531..1140727 100644
--- a/index.html
+++ b/index.html
@@ -21,7 +21,7 @@
   
   
     
Skip to content

许大仙同学

『这个世纪疯狂,没人性,腐败;你却一直清醒,温柔,一尘不染。』

Released under the MIT License.

- + \ No newline at end of file diff --git a/notes/01_c-basic/00_xdx/index.html b/notes/01_c-basic/00_xdx/index.html index ebccca6..a6701ef 100644 --- a/notes/01_c-basic/00_xdx/index.html +++ b/notes/01_c-basic/00_xdx/index.html @@ -67,7 +67,7 @@ }
  • 编程语言就是用于控制计算机,让其完成我们需要的功能。而我们学习编程语言,其实就是学习这些文字和符号编写的规则。
  • 因为 CPU 只能识别二进制的指令,而我们编写的程序叫做源代码,是人类能看懂;但是,计算机却不能识别。那么,我们就需要让计算机能识别我们编写的源程序,就需要将我们编写的源代码交给编译器程序,其会帮助我们将所编写的源代码转换为计算机能够识别的二进制指令。

NOTE

编译器就是运行在操作系统之上的程序,其作用就是用来将程序员编写的源代码转换为计算机能够识别的二进制指令。

  • 如果我们用 Java 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Java 语言的编译器将 Java 程序编译为计算机能够识别的二进制指令。
  • 如果我们用 Python 语言编写了程序(源代码),那么编写的程序也是不能直接运行的,需要通过 Python 语言的编译器将 Python 程序编译为计算机能够识别的二进制指令。
  • ……
  • 总而言之,无论我们学习任何一门编程语言,想要将程序运行起来,都必须做如下的两件事情:
    • ① 学习该语言的文字和符号编写的规则,即:语法规则
    • ② 需要在操作系统上安装对应编程语言的编译器程序,将源程序编译为计算机能够识别的二进制指令。

2.3 计算机语言简史

2.3.1 机器语言(相当于人类的石器时代)

  • 1946 年 2 月 14 日,世界上第一台计算机 ENIAC 诞生,使用的是最原始的穿透卡片

  • 这种卡片使用的是用二进制代码表示的语言,和人类语言差别极大,这种语言就称为机器语言,如:
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)代替二进制操作码,使程序更易于人类编写和理解;因此,汇编语言也被称为符号语言

  • 汇编语言的优点是能编写高效率的程序;但是,缺点和机器语言没什么不同,汇编语言同样依赖于具体的计算机架构(面向机器),程序不具备跨平台的可移植性。

NOTE

汇编语言,目前仍然应用于工业电子编程领域、软件的加密解密、计算机病毒分析等。

2.3.3 高级语言(相当于人类的信息时代)

  • 高级语言是一种接近于人们使用习惯的程序设计语言。它允许程序员使用接近日常英语的指令来编写程序,程序中的符号和算式也和日常使用的数学公式差不多,接近于自然语言和数学语言,容易被人们掌握。

  • 高级语言独立于计算机硬件,有一定的通用性;计算机不能直接识别和执行用高级语言编写的程序,需要使用编译器解释器转换为机器语言,才能被计算机识别和执行。

NOTE

普遍使用的高级编程语言,有:C、C++、Java、Python、C#、JavaScript、Go、SQL 等。

2.3.4 总结

  • 编写语言的对比,如下所示:
类别特征优点缺点示例
机器语言直接由计算机执行的二进制代码执行速度快编写困难,可读性差,与具体硬件强绑定二进制代码
汇编语言用助记符代替二进制代码的低级语言相对机器语言更易编写和理解,允许直接控制硬件资源依然需要了解硬件,不够抽象,与具体硬件或平台相关MOV,ADD 等助记符
高级语言接近人类语言,提供了更高层次的抽象易于编写和维护,可移植性好,支持多种编程范式需要通过编译器或解释器转换为机器语言,可能存在一定的性能损失C,Java, Python 等

NOTE

  • ① 这三种编程语言类型从低级到高级提供了不同层次的抽象,以满足不同的编程需求和场景。
  • ② 随着计算机科学的发展,高级语言因其强大的表达能力、良好的可移植性和易用性,成为了日常软件开发的主流选择。

第三章:初识 C 语言

3.1 C 语言的由来

  • 1969 年,美国贝尔实验室的肯·汤姆森(Ken Thompson)和丹尼斯·里奇(Dennis Ritchie)一起开发了 Unix 操作系统。Unix 最初是使用汇编语言编写的,依赖于计算机硬件。为了程序的可读性可移植性,它们决定使用高级语言重写。但是。当时的高级语言无法满足他们的要求,肯·汤姆森就在 BCPL 语言的基础上发明了 B 语言。
  • 1972 年,丹尼斯·里奇(Dennis Ritchie)在 B 语言的基础上重新设计了一种新的语言,这种新语言取代了 B 语言,即 C 语言。

  • 1973 年,整个 Unix 系统都使用 C 语言重写

NOTE

C 语言最初是作为 Unix 系统的开发工具而发明的。

  • 此后,这种语言快速流传,广泛用于各种操作系统和系统软件的开发,如:Unix、MS-DOS、Microsoft Windows 以及 Linux 等。

  • 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 是一个流行编程语言排行,每月更新。排名权重基于世界范围内工程师数量,Google、Bing、Yahoo! 、Wikipedia、Amazon、Youtube 和百度这些主流的搜索引擎,也将作为排名权重的参考指标。

  • 计算机语言走势图:

3.4 C 语言的版本选择

  • 随着微型计算机的日益普及,出现了许多 C 语言版本(标准):

    • 版本 1(K&R C):K&R C 指的是 C 语言的原始版本。1978年,C 语言的发明者布莱恩·柯林(Brian Kernighan)和丹尼斯·里奇(Dennis Ritchie)合写了一本著名的教材《C 编程语言》(The C programming language)。

    NOTE

    由于 C 语言还没有成文的语法标准,这本书就成了公认标准,以两位作者的姓氏首字母作为版本简称 “K&R C”。

    • 版本 2(ANSI C,又称 C89 或 C90):C 语言的原始版本非常简单,对很多情况的描述非常模糊,加上 C 语法依然在快速发展,要求将 C 语言标准化的呼声越来越高。1989 年,美国国家标准协会(ANSI)制定了一套 C 语言标准,并于次年被国际标准化组织(ISO)通过。它被称为 “ANSI C”,也可以按照发布年份,称为 “C89 或 C90”。

    • 版本 3(C99):C 语言标准的第一次大型修订,发生在 1999 年,增加了许多语言特性,比如:双斜杠( // )的注释语法,可变长度数组、灵活的数组成员、复数、内联函数和指定的初始值设定项,这个版本称为 C99,是目前最流行的 C 版本

    • 版本 4(C11):2011 年,标准化组织再一次对 C 语言进行修订,增加了_Generic、static_assert 和原子类型限定符。这个版本称为 C11。

    NOTE

    需要强调的是,修订标准的原因并不是因为原标准不能用,而是需要跟进新的技术。

    • 版本 5(C17):C11 标准在 2017 年进行了修补,但发布是在 2018 年。新版本只是解决了 C11 的一些缺陷,没有引入任何新功能。这个版本称为 C17。
    • 版本 6(C23):2023 年发布,计划进一步增强安全性,消除实现定义的行为,引入模块化语言概念等新特性,使 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、可执行文件等)。
    • 依赖管理:自动下载、更新和管理项目所需的第三方库(这部分功能有时与包管理器重叠)。
    • 部署:将打包后的应用程序自动部署到测试环境、生产环境等。
    • 任务自动化:除了基本的构建流程外,还可以自动化执行一些常见任务,如:代码检查、文档生成等。
  • 常用的项目构建工具:
    • Maven(Java):一个流行的构建工具和依赖管理工具,广泛用于 Java 项目。
    • Gradle(Java、Kotlin、Groovy):一个灵活的构建工具,支持声明式的构建脚本和多种语言。
    • Make(C/C++):一个经典的构建工具,使用 Makefile 来定义构建规则和依赖关系。
    • Ant(Java):早期流行的 Java 构建工具,通过 XML 配置文件定义构建过程。
    • CMake(C/C++):一个跨平台的构建系统,帮助生成标准的构建文件,如:Makefile 或 Visual Studio 项目文件。

4.2.3 包管理器

  • 包管理器是用于自动化安装、更新、配置管理软件包及其依赖关系的工具。它主要关注于获取和管理项目所需的第三方库或工具包,并确保它们正确地集成到项目中。
  • 其功能有:
    • 依赖管理:根据项目配置文件(如:package.jsonrequirements.txt)自动下载和安装项目所需的依赖包。
    • 版本控制:管理包的版本,允许开发者指定某个特定版本或版本范围,确保项目中的库版本一致性。
    • 包的发布和共享:开发者可以通过包管理器发布自己的库,并且共享给社区或组织内部的其他项目使用。
    • 环境隔离:有些包管理器提供虚拟环境功能,可以将不同项目的依赖隔离开,避免版本冲突。
    • 更新和卸载:包管理器可以自动更新依赖包到最新的兼容版本或卸载不再需要的包。
  • 常见的包管理器:
    • npm(Node.js):用于管理 JavaScript 和 Node.js 项目的包和模块。
    • pip(Python):用于安装和管理 Python 的软件包。
    • Composer(PHP):用于管理 PHP 项目的依赖库。
    • NuGet(.NET):用于管理 .NET 平台上的包和库。
    • RubyGems(Ruby):用于管理 Ruby 的库和工具包。
    • Cargo(Rust):Rust 编程语言的包管理器和构建工具。
    • Yarn(JavaScript):是 npm 的替代品,提供更快和更可靠的包管理体验。
    • Homebrew(macOS):用于 macOS 系统下的命令行工具和库的管理。

4.2.3 注意事项

  • 对于 Java 项目中的 MavenGradle 而言,其不仅是项目构建工具也是包管理工具

第五章:附录

5.1 嵌入式领域中的 C 语言

5.1.1 概述

  • C 语言在 C51、STM32 和 ARM 平台上的应用场景非常广泛,涵盖了各种嵌入式系统的开发需求。

5.1.2 C51(8051 系列微控制器)

  • 背景:8051 是由 Intel 于 1980 年设计的一种 8 位微控制器架构。它具有指令集简单、结构紧凑的特点,广泛应用于低端嵌入式系统中。
  • 开发工具:C51 是指针对 8051 系列微控制器的 C 语言编译器,如:Keil C51。这种编译器将 C 语言代码编译为适合 8051 架构的汇编代码。
  • C 语言的作用:C 语言在 8051 微控制器上的应用使得开发更加高效和可维护。尽管 8051 的硬件资源有限,但 C 语言仍然能够在不损失性能的前提下提供高级编程的便利。
  • 应用场景
    • 简单的控制系统:家用电器(微波炉、洗衣机、空调)的控制板等。这些设备通常不需要复杂的运算能力,但要求可靠和稳定的控制。
    • 低功耗传感器接口:C51 微控制器常用于低功耗传感器的数据采集和传输,如:温度、湿度、压力传感器。
    • 工业自动化设备:用于简单的工业自动化控制,如:小型电机驱动、工业传感器数据处理和传输。
    • 电子玩具:许多简单的电子玩具使用 8051 系列微控制器来控制声音、LED 灯光、显示屏等。

NOTE

总结:C51 微控制器适用于资源受限、需要低成本的简单控制系统,非常适合使用 C 语言来进行开发!!!

5.1.3 STM32(STM32 系列微控制器)

  • 背景:STM32 是意法半导体(STMicroelectronics)推出的一系列基于 ARM Cortex-M 内核的 32 位微控制器。它们广泛用于需要高性能和低功耗的嵌入式应用中,如:工业控制、消费电子和物联网设备。
  • 开发工具:开发 STM32 微控制器通常使用 Keil、IAR Embedded Workbench 或 STM32CubeIDE 等开发环境。这些环境中使用的编程语言主要是 C(有时也包括 C++)。
  • C 语言的作用:C 语言在 STM32 上的应用非常广泛,开发者可以利用它直接控制硬件寄存器,同时也能方便地使用 STM32 提供的 HAL(硬件抽象层)库或 LL(低层)库进行开发。C 语言在这个平台上不仅能实现底层控制,还能编写复杂的应用逻辑。
  • 应用场景
    • 物联网(IoT)设备:STM32 微控制器常用于各种物联网设备,如:智能家居控制系统、环境监测设备、可穿戴设备等。这些设备通常需要低功耗和强大的处理能力,并且需要支持多种通信协议,如:Wi-Fi、Bluetooth、LoRa。
    • 消费电子:智能手表、健身追踪器、电子书阅读器、无人机等,这些设备需要具备实时处理能力、低功耗和良好的外设支持。
    • 医疗设备:STM32 微控制器被广泛应用于便携式医疗设备中,如:血糖监测仪、心率监测器、便携式超声设备等,这些设备需要精确的传感器数据采集和处理。
    • 工业自动化控制:PLC(可编程逻辑控制器)、工业机器人、伺服电机控制等,STM32 能够处理复杂的控制算法和实时任务。
    • 汽车电子:用于汽车中的传感器管理、车载信息娱乐系统、车身控制系统(车窗、电动座椅调节等)。

NOTE

总结:STM32 微控制器在物联网、消费电子、医疗设备和工业控制等领域表现出色,非常适合使用 C 语言来进行开发,因为 C 语言允许直接进行硬件控制并支持复杂的应用开发。

5.1.3 ARM 架构(特别是 ARM Cortex 系列)

  • 背景:ARM 是一种广泛使用的处理器架构,特别是在嵌入式系统中,ARM Cortex 系列处理器(如 Cortex-M、Cortex-R 和 Cortex-A)非常流行。Cortex-M 系列主要用于微控制器,Cortex-R 用于实时系统,Cortex-A 则用于高性能嵌入式系统。
  • 开发工具:针对 ARM 架构的开发,常用工具包括 ARM Keil MDK、IAR、GCC for ARM 和 ARM Development Studio。这些工具均支持使用 C 语言进行开发。
  • C 语言的作用:C 语言在 ARM 架构上的应用广泛。它被用于操作系统内核(如 FreeRTOS、Zephyr)、设备驱动、应用层逻辑等。在 ARM Cortex-M 和 Cortex-R 系列中,C 语言的高效性和低级别硬件访问能力是开发实时、低延迟系统的关键。
  • 应用场景
    • 高级嵌入式操作系统:ARM Cortex-A 系列处理器广泛用于运行 Linux、Android 等操作系统的嵌入式设备,如:智能手机、平板电脑、智能电视和车载娱乐系统。
    • 实时系统:ARM Cortex-R 系列处理器用于实时系统,如:汽车的 ABS(防抱死制动系统)、ESC(电子稳定控制系统),以及航空电子设备,这些系统要求极低的延迟和高可靠性。
    • 高性能物联网网关:Cortex-A 系列处理器可以用来开发支持多协议、多设备管理的物联网网关,这些网关通常需要强大的计算能力和多线程处理能力。
    • 边缘计算设备:在边缘计算场景中,ARM Cortex-A 处理器用于执行本地数据处理和决策,如:视频分析、图像处理、语音识别等。
    • 智能家居设备:ARM Cortex-M 系列微控制器广泛应用于智能家居产品,如:智能灯泡、智能音箱、家庭安全系统,这些设备需要高效的处理能力和低功耗。
    • 机器人控制系统:ARM Cortex-M 和 Cortex-A 系列处理器用于机器人系统的控制和通信,如:无人机、工业机器人、服务机器人等,处理复杂的运动控制、路径规划和传感器数据融合。

NOTE

总结:ARM Cortex 系列适用于从实时系统到高级嵌入式操作系统的各类应用,支持从低功耗控制到高性能计算的多种需求,非常适合使用 C 语言来进行开发,因为 C 语言不仅用于控制硬件,还广泛应用于操作系统和应用程序的开发。

- + \ No newline at end of file diff --git a/notes/01_c-basic/01_xdx/index.html b/notes/01_c-basic/01_xdx/index.html index 222f01f..886c0b2 100644 --- a/notes/01_c-basic/01_xdx/index.html +++ b/notes/01_c-basic/01_xdx/index.html @@ -303,7 +303,7 @@ --depth 1 \ --single-branch --branch=linux-msft-wsl-${KERNEL_VERSION} \ https://github.com/microsoft/WSL2-Linux-Kernel.git

shell
cd WSL2-Linux-Kernel
shell
make -j $(nproc) KCONFIG_CONFIG=Microsoft/config-wsl

shell
cd tools/perf
shell
make clean && make

shell
cp perf /usr/bin/

8.4.3 整合

8.5 Win 中文乱码问题

NOTE

8.6 CLion 中自动导入头文件

NOTE

- + \ No newline at end of file diff --git a/notes/01_c-basic/02_xdx/index.html b/notes/01_c-basic/02_xdx/index.html index d96e375..91d9f77 100644 --- a/notes/01_c-basic/02_xdx/index.html +++ b/notes/01_c-basic/02_xdx/index.html @@ -260,7 +260,7 @@ return 0; }

3.3 进制的运算规则

3.4 进制的转换

3.4.1 概述

3.4.2 二进制和十进制的转换

3.4.2.1 二进制转换为十进制

NOTE

3.4.2.2 十进制转换二进制

NOTE

3.4.3 二进制转八进制

3.4.4 二进制转十六进制

3.5 原码、反码和补码

3.5.1 概述

3.5.2 原码

十进制数原码(8位二进制数)
+10000 0001
十进制数原码(8位二进制数)
-11000 0001

IMPORTANT

按照原码的规则,会出现 +0-0 的情况,即:0000 0000(+0)、1000 0000(-0),显然不符合实际情况;所以,计算机底层虽然存储和计算的都是二进数,但显然不是原码。

3.5.3 反码

十进制数原码(8位二进制数)反码(8位二进制数)
+10000 00010000 0001
十进制数原码(8位二进制数)反码(8位二进制数)
-11000 00011111 1110

IMPORTANT

按照反码的规则,如果是 +0,对应的原码是 0000 0000;那么,其反码还是 0000 0000 ;如果是 -0,对应的原码是 1000 0000,其反码是 1111 1111,显然不符合实际情况;所以,计算机底层虽然存储和计算的都是二进数,但显然不是反码。

3.5.4 补码

十进制数原码(8位二进制数)反码(8位二进制数)补码(8位二进制数)
+10000 00010000 00010000 0001
十进制数原码(8位二进制数)反码(8位二进制数)补码(8位二进制数)
-11000 00011111 11101111 1111

IMPORTANT

3.5.5 总结

3.6 计算机底层为什么使用补码?

- + \ No newline at end of file diff --git a/notes/01_c-basic/03_xdx/index.html b/notes/01_c-basic/03_xdx/index.html index bb365a6..873058f 100644 --- a/notes/01_c-basic/03_xdx/index.html +++ b/notes/01_c-basic/03_xdx/index.html @@ -789,7 +789,7 @@ return 0; }

2.8 运算符优先级

优先级运算符名称或含义结合方向
1[]数组下标➡️(从左到右)
()圆括号
.成员选择(对象)
->成员选择(指针)
2-负号运算符⬅️(从右到左)
(类型)强制类型转换
++自增运算符
--自减运算符
*取值运算符
&取地址运算符
!逻辑非运算符
~按位取反运算符
sizeof长度运算符
3/➡️(从左到右)
*
%余数(取模)
4+➡️(从左到右)
-
5<<左移➡️(从左到右)
>>右移
6>大于➡️(从左到右)
>=大于等于
<小于
<=小于等于
7==等于➡️(从左到右)
!=不等于
8&按位与➡️(从左到右)
9^按位异或➡️(从左到右)
10|按位或➡️(从左到右)
11&&逻辑与➡️(从左到右)
12||逻辑或➡️(从左到右)
13?:条件运算符⬅️(从右到左)
14=赋值运算符⬅️(从右到左)
/=除后赋值
*=乘后赋值
%=取模后赋值
+=加后赋值
-=减后赋值
<<=左移后赋值
>>=右移后赋值
&=按位与后赋值
^=按位异或后赋值
|=按位或后赋值
15,逗号运算符➡️(从左到右)

WARNING

第三章:附录

3.1 字符集和字符集编码

3.3.1 概述

NOTE

ASCII(美国信息交换标准代码)是最早期和最简单的字符集之一,它只包括了英文字母、数字和一些特殊字符,共 128 个字符。每个字符都分配给了一个从 0 到 127 的数字。

NOTE

ASCII 编码方案定义了如何将 ASCII 字符集中的每个字符表示为 7 位的二进制数字。例如:大写字母'A'在 ASCII 编码中表示为二进制的1000001,十进制的 65

3.3.2 ASCII 编码

NOTE

shell
man ascii

NOTE

3.3.3 Unicode 编码

- + \ No newline at end of file diff --git a/notes/01_c-basic/04_xdx/index.html b/notes/01_c-basic/04_xdx/index.html index 53d9d9c..b1662da 100644 --- a/notes/01_c-basic/04_xdx/index.html +++ b/notes/01_c-basic/04_xdx/index.html @@ -772,7 +772,7 @@ return 0; } - + \ No newline at end of file diff --git a/notes/01_c-basic/05_xdx/index.html b/notes/01_c-basic/05_xdx/index.html index 70beb16..c129a02 100644 --- a/notes/01_c-basic/05_xdx/index.html +++ b/notes/01_c-basic/05_xdx/index.html @@ -720,7 +720,7 @@ return 0; }

WARNING

在上述示例中,arr&arr 的值是一样的,但是对应的含义是不同的。

- + \ No newline at end of file diff --git a/notes/01_c-basic/06_xdx/index.html b/notes/01_c-basic/06_xdx/index.html index f7acff1..77c9a0d 100644 --- a/notes/01_c-basic/06_xdx/index.html +++ b/notes/01_c-basic/06_xdx/index.html @@ -12,7 +12,7 @@ - + @@ -45,7 +45,7 @@ int num = 10; return 0; -}

NOTE

通过内存地址找到所需要的存储单元,即:内存地址指向该存储单元。此时,就可以将内存地址形象化的描述为指针👉,那么:

总结:内存地址 = 指针。

NOTE

有的时候,为了方便阐述,我们会将指针变量称为指针。但是,需要记住的是:

下文中提及的指针都是指针变量,不再阐述!!!

WARNING

如果你观察仔细的话,你可能会发现指针变量普通变量在内存中占据的存储空间是不一样的,那么到底是什么原因造成这样的结果?

3.3 指针变量的定义

3.4 指针的作用

在 Java 中,引用数据类型的向上类型转换(upcasting)和向下类型转换(downcasting)是面向对象编程中常见的操作。这些转换是 Java 继承体系和多态性的重要部分。我们先分别介绍向上类型转换和向下类型转换,然后讨论它们在 C 语言中指针的类似操作。

向上类型转换(Upcasting)

向上类型转换是将一个子类对象引用转换为父类对象引用。由于子类继承了父类的所有方法和属性,子类对象也包含父类对象的所有部分,因此这种转换是安全且隐式的。

例子:

java
class Animal {
+}

NOTE

通过内存地址找到所需要的存储单元,即:内存地址指向该存储单元。此时,就可以将内存地址形象化的描述为指针👉,那么:

总结:内存地址 = 指针。

NOTE

有的时候,为了方便阐述,我们会将指针变量称为指针。但是,需要记住的是:

下文中提及的指针都是指针变量,不再阐述!!!

WARNING

如果你观察仔细的话,你可能会发现指针变量普通变量在内存中占据的存储空间是不一样的,那么到底是什么原因造成这样的结果?

3.3 指针变量的定义

3.4 指针的作用

在 Java 中,引用数据类型的向上类型转换(upcasting)和向下类型转换(downcasting)是面向对象编程中常见的操作。这些转换是 Java 继承体系和多态性的重要部分。我们先分别介绍向上类型转换和向下类型转换,然后讨论它们在 C 语言中指针的类似操作。

向上类型转换(Upcasting)

向上类型转换是将一个子类对象引用转换为父类对象引用。由于子类继承了父类的所有方法和属性,子类对象也包含父类对象的所有部分,因此这种转换是安全且隐式的。

例子:

java
class Animal {
     void makeSound() {
         System.out.println("Animal sound");
     }
@@ -101,7 +101,7 @@
 
 printf("Address of array: %p\n", &arr);  // 返回整个数组的地址
 printf("Address of pointer: %p\n", &ptr);  // 返回指针变量ptr的地址

综上所述,通过这些示例和解释,可以看出数组名虽然在某些场合下可以像指针一样使用,但它并不是一个真正的指针变量,而是一个常量,表示数组的首地址。

- + \ No newline at end of file diff --git a/notes/04_linux/01_xdx/index.html b/notes/04_linux/01_xdx/index.html index ba9e7ec..e190a06 100644 --- a/notes/04_linux/01_xdx/index.html +++ b/notes/04_linux/01_xdx/index.html @@ -21,7 +21,7 @@
Skip to content

第一章:Linux

1.1 Linux 概述

  • Linux 是一种开源的操作系统,最初由芬兰的林纳斯·托瓦兹(Linus Torvalds)开发。它基于 UNIX 操作系统,并且具有高度的可定制性和灵活性。Linux 操作系统被广泛应用于服务器、嵌入式系统和个人计算机等领域。
  • 它具有稳定性、安全性和可靠性,并且支持多用户、多任务和多线程。Linux 拥有众多的发行版,如:Ubuntu、Red Hat、Debian 等,每个发行版都有自己的特点和优势。
  • 由于其开源性质,Linux 操作系统受到了全球开发者的广泛支持和贡献,成为了计算机行业中的重要组成部分。

1.2 Linux 的发展史

  • Linux 的发展历史可以分为以下几个阶段:

    • ① 初始阶段(1991 - 1994 年):林纳斯·托瓦兹在 1991 年发布了 Linux 内核的第一个版本,并将其开源。在接下来的几年里,Linux 逐渐吸引了一些开发者的关注和参与,开始逐步完善和扩展功能。
    • ② 发展阶段(1995 - 2000 年):在这个阶段,Linux 开始受到更多人的关注和认可。许多开发者和公司开始为 Linux 开发应用程序和驱动程序,为其增加更多的功能和兼容性。同时,一些发行版如:Red Hat、Debian 等也开始出现,为用户提供了更方便的安装和使用方式。
    • ③ 商业化阶段(2001 - 至今):随着 Linux 的成熟和广泛应用,越来越多的公司开始将 Linux 作为服务器和嵌入式设备的操作系统。一些大型科技公司,如:IBM、Oracle 等也开始投入大量资源支持 Linux 的发展。同时,一些商业化的 Linux 发行版,如:SUSE、Ubuntu 等也崭露头角,为企业和个人用户提供了更专业的支持和服务。
    • ④ 社区发展阶段:Linux 的发展一直依赖于全球开发者社区的贡献和支持。Linux 社区不断壮大,吸引了众多的开发者和爱好者参与其中。通过社区的力量,Linux 不断更新迭代,推出了许多新的版本和功能。
  • 总的来说,Linux 的发展历程是一个由个人项目逐渐发展为全球开源社区支持的过程。它的成功得益于开源模式的优势,以及全球开发者的共同努力和贡献。

1.3 Linux 的组成(⭐)

  • Linux 主要由以下几个组成部分构成:

    • Linux 内核:Linux 内核是整个操作系统的核心,负责管理硬件设备、内存管理、进程调度等核心功能。它是由林纳斯·托瓦兹及其他开发者编写和维护的。
    • Shell 解释器:Shell 解释器是用户与操作系统交互的接口,它接收用户输入的命令并将其解释执行。常见的 Shell 解释器有 Bash、Zsh 等,它们提供了命令行界面和脚本编程功能。
    • 外围的应用程序:命令、应用程序、图形化界面……
  • 其图示如下:

image-20240115214505877

  • 上述的组成部分共同构成了一个完整的 Linux 操作系统,为用户提供了丰富的功能和灵活性。

1.4 Linux 发行版本(⭐)

  • Linux 发行版本就是:Linux 内核 + 命令解释器 + 应用程序(桌面)
  • 主流的 Linux 发行版本如下:
Linux 系统类别Linux 系统备注
Debian 系列Debian更新频率较低,较为稳定和安全,可以用于企业生产环境。
Ubuntu桌面美观,使用方便,开发使用。有桌面版和企业版本(服务器版本)。
Redhat 系列RedHat Enterprise Linux(RHEL红帽企业版本
CentOS基于 Red Hat Enterprise Linux(RHEL)源代码构建的免费开源操作系统。它提供了企业级的稳定性和安全性,广泛用于服务器环境。
FedoraFedora 是由 Red Hat 赞助的社区驱动的 Linux 发行版,注重最新的软件和技术。它提供了一个先进的桌面环境和开发者工具。
Rocky Linux用来替代 CentOS 系统的,也是基于 Red Hat Enterprise Linux(RHEL)源代码构建的免费开源操作系统。
Alma Linux用来替代 CentOS 系统的,也是基于 Red Hat Enterprise Linux(RHEL)源代码构建的免费开源操作系统。
其它系列SUSE、OpenSUSEOpenSUSE 是一个用户友好且功能强大的 Linux 发行版,具有稳定性和灵活性。它提供了多种桌面环境和服务器选项。
  • 当然,除了以上几个主流的 Linux 发行版,还有许多其他的发行版,如:Arch Linux、Gentoo、Mageia 等,它们各自有着不同的特点和适用场景。
  • 选择适合自己需求的发行版是根据个人或组织的需求和偏好来决定的。

1.5 Linux 版本选择(⭐)

  • 推荐选择 LTS 版稳定版

WARNING

  • LTS 是 "Long-Term Support" 的缩写,意为长期支持。在软件开发领域,LTS 通常用来描述某个版本或发行版的长期支持周期。
  • 对于 Linux 发行版或其他软件,LTS 版本通常会提供更长时间的支持和维护,以确保稳定性和安全性。这意味着在 LTS 版本的支持周期内,开发者会持续提供安全补丁、错误修复和其他重要更新,以保持系统的稳定性和可靠性。
  • LTS 版本通常适用于企业和组织等需要长期稳定性和可靠性的环境。相比于非 LTS 版本,LTS 版本的更新频率较低,更注重于提供长期支持和维护。
  • 本次选择:
系统版本说明
UbuntuLTS 18.04 、LTS 20.04 等
AlmaLinux9.1、9.2、9.3 等

第二章:工作和学习环境部署(⭐)

2.1 服务器

  • 服务器是一种专门用于提供服务的计算机系统。它通常具有更高的性能、可靠性和稳定性,以满足处理大量请求和提供持续服务的需求。
  • 服务器的主要功能是接收来自客户端的请求,并提供相应的服务或资源。这些服务可以包括:网站托管、数据库管理、文件存储、电子邮件、应用程序运行等。服务器通过网络与客户端进行通信,处理请求并返回相应的数据或结果。
  • 服务器通常采用高性能的硬件配置,如:多核处理器、大容量内存、高速存储设备等,以确保能够处理大量的并发请求。它们还通常具有冗余的设计,包括冗余电源、冗余网络连接和冗余存储等,以提高可靠性和可用性。
  • 服务器可以是物理服务器,即实际的硬件设备,也可以是虚拟服务器,即在物理服务器上通过虚拟化技术创建的虚拟机。无论是物理服务器还是虚拟服务器,它们都扮演着提供服务和资源的角色。
  • 在企业和组织中,服务器通常由专门的 IT 团队进行管理和维护。他们负责服务器的配置、安全性、性能优化、备份和恢复等工作,以确保服务器的稳定运行和数据的安全性。

TIP

实际工作的时候,Linux 系统会运行在服务器上。

2.2 虚拟机概述

  • 虚拟机(Virtual Machine,简称 VM)是一种软件实现的计算机系统,它在物理计算机上模拟出一个完整的计算环境。虚拟机可以在同一台物理计算机上同时运行多个独立的操作系统和应用程序。

2

  • 虚拟机的工作原理是通过虚拟化技术将物理计算机的硬件资源(如:处理器、内存、存储等)进行抽象和分配,为每个虚拟机提供一部分资源。每个虚拟机都被视为一个独立的计算机系统,可以运行自己的操作系统和应用程序。
  • 虚拟机的优势在于它可以提供隔离性灵活性。通过虚拟机,可以在同一台物理计算机上同时运行多个操作系统,实现资源的共享和最大化利用。同时,虚拟机还可以提供快速部署、快速备份和恢复等功能,方便管理和维护。
  • 常见的虚拟机软件,包括:VMware、VirtualBox、KVM 等。它们提供了虚拟化平台和管理工具,使用户可以轻松创建、配置和管理虚拟机。虚拟机广泛应用于开发和测试环境、服务器虚拟化、云计算等领域。

WARNING

虚拟机软件虚拟机的概念不同:

  • 虚拟机软件是用来模拟硬件一个软件,如:VMware 等。
  • ② 而虚拟机是通过虚拟机软件模拟出来的计算机硬件,其实是文件的集合,相当于一台没有安装 Windows 操作系统的裸机
  • ③ 在现实交谈的时候,我们有时候会模糊虚拟机软件虚拟机的概念,甚至会使用虚拟机来代替虚拟机软件;此时,就需要根据上下文环境(语境)来判断到底说的是虚拟机软件还是虚拟机了。

2.3 安装虚拟机软件

2.3.1 前提条件

  • 需要在 BIOS 中开启虚拟化功能。

image-20240117085245337

2.3.2 安装步骤

  • ① 双击打开 VMware 安装程序 。

双击打开VMware安装程序.png

  • ② 进行下一步安装:

VMware进行下一步安装.png

  • ③ 同意许可协议,单击下一步:

VMware同意许可协议,单击下一步.png

  • ④ 根据需要决定是否需要更改软件的安装位置(建议放置于除 C 盘以外任意盘符下):

VMware更改安装位置.png

VMware更改安装位置成功.png

  • ⑤ 更改成功后,单击确定,下一步继续安装:

VMware更改成功后,单击确定,下一步继续安装.png

  • ⑥ 用户体验设置,如下图所示,单击下一步继续安装:

VMware用户体验设置,如下图所示,单击下一步继续安装.png

  • ⑦ 快捷方式设置,单击下一步继续安装:

VMware快捷方式设置,单击下一步继续安装.png

  • ⑧ 单击安装按钮:

VMware单击安装按钮.png

  • ⑨ VMware 输入许可证:

VMware单击许可证.png

VMware输入许可证.png

  • ⑩ 安装结束后,单击完成按钮:

VMware安装结束后,单击完成按钮.png

  • ⑪ 检查虚拟机软件是否安装了虚拟网卡:

查看VMware安装的虚拟网卡.png

查看VMware安装的虚拟网卡1.png

查看VMware安装的虚拟网卡2.png

2.3.2 配置网络

  • ① 打开 VMware 虚拟机软件:

image-20240116202917529

  • ② 编辑 → 虚拟网络编辑器:

image-20240116202955131

  • ③ Vmnet8 → 更改设置:

image-20240116203207282

  • ④ 更改子网 IP 地址为 :192.168.10.0 ,其目的是为了将 IP 固定。

image-20240116203357894

  • ⑤ DHCP 设置:

image-20240116203529749

image-20240116203627959

  • ⑤ 通过 cmd ,输入 ipconfig 命令,查看是否配置成功:

2.4 创建虚拟机

2.4.1 概述

  • 创建虚拟机,本质上就类似购买一台没有安装操作系统的裸机

2.4.2 创建虚拟机

  • ① 文件 → 新建虚拟机:

image-20240117090352182

  • ② 选择自定义类型的配置:

image-20240117090443216

  • ③ 虚拟机硬件兼容性:下一步即可。

image-20240117090529266

  • ④ 选择稍后安装操作系统

image-20240117090636337

  • ⑤ 选择虚拟机将安装的操作系统:

image-20240117090805295

  • ⑥ 设置虚拟机的名称安装位置

image-20240117090944676

WARNING

一个虚拟机一个安装目录(文件夹),防止引起文件的冲突。

  • ⑦ 虚拟机中处理器的配置:下一步即可。

image-20240117091051284

  • ⑧ 设置虚拟机的内存:至少 2048 MB以上。

image-20240117091202131

  • ⑨ 设置虚拟机的网络类型:下一步即可。

image-20240117091257738

  • ⑩ 设置 I/O 控制器类型:下一步即可。

image-20240117091402913

  • ⑪ 选择磁盘类型:下一步即可。

image-20240117091540264

  • ⑫ 选择磁盘:下一步即可。

image-20240117091640870

  • ⑬ 选择磁盘容量:调整为 40 GB。

image-20240117091832846

  • ⑭ 指定磁盘文件:下一步即可。

image-20240117091907233

  • ⑮ 创建虚拟机完毕:

image-20240117092013264

  • ⑯ 查看是否创建虚拟机成功:

image-20240117092101810

2.4.3 虚拟机归类(分类)

  • 实际情况下,我们可能会创建很多虚拟机,VMware 提供了文件夹的功能来管理虚拟机;其步骤如下所示:
  • ① 鼠标右键 → 创建文件夹:

image-20240117092324545

  • ② 修改文件夹的名称:

image-20240117092600931

image-20240117092643086

image-20240117092720769

  • ③ 将刚才创建的虚拟机到该文件夹下:

2.4.4 设置 CD/DVD

  • 以前,我们在一台裸机上安装操作系统的时候,需要通过 DVD 或 U 盘将操作系统的 ISO 镜像文件,安装到裸机上;
  • 同理,在使用虚拟机软件的时候,也需要此类步骤;其步骤如下:
  • ① 编辑虚拟机设置:

image-20240117093143947

  • ② 选择硬盘上的 ISO 镜像文件:

image-20240117093354461

  • ③ 查看是否配置成功:

image-20240117093435976

2.5 安装 Linux

  • 开启此虚拟机

image-20240117093516070

  • 鼠标点击进去之后,通过键盘上的方向键来选择:

image-20240117093610205

  • 注意⚠️:键盘上的方向键在这里

image-20240117093918602

  • ③ 设置操作系统的语言环境为中文

image-20240117094530342

  • ④ 设置系统安装目的地

  • ⑤ 设置软件选择:默认即可

  • ⑥ 设置 root 的密码:123456即可

WARNING

学习阶段无所谓设置什么密码,但是生产环境,必须复杂并且经常更换!!!

  • ⑦ 配置网络和主机名

image-20240224223931266

image-20240224224038036

image-20240224224138061

image-20240224224209724

image-20240224224245924

image-20240224224344051

  • ⑧ 查看配置网络和主机名是否成功:

image-20240224224420273

  • ⑨ 点击开始安装:漫长的等待……

  • ⑩ 安装完成之后,会提示重启系统,那就重启吧:

2.6 远程连接 Linux

2.6.1 查看 Linux 的 IP 地址

  • 通过 ifconfig 命令来查看 Linux 的 IP 地址:
shell
ifconfig

image-20240117101543732

2.6.2 远程连接 Linux

  • 可以通过 xshell 之类的远程连接工具来连接 Linux ,其步骤如下:
  • ① 新建会话:

image-20240117101749340

  • ② 输入 Linux 的 IP 地址:

image-20240117101906927

  • ③ 输入用户名和密码:

image-20240117102005340

  • ④ 接收和保存远程 Linux 的密钥:

image-20240117102123845

  • ⑤ 查看是否登录成功:

image-20240117102159684

Released under the MIT License.

- + \ No newline at end of file diff --git a/notes/index.html b/notes/index.html index 330c292..83e189c 100644 --- a/notes/index.html +++ b/notes/index.html @@ -21,7 +21,7 @@
Skip to content

c/c++ 学科


Released under the MIT License.

- + \ No newline at end of file