From 882339735ceaa6bafb9f7888514392281647bb4d Mon Sep 17 00:00:00 2001 From: Aurorxa Date: Thu, 11 Jul 2024 09:31:25 +0000 Subject: [PATCH] deploy: 9a39b21452170b168026334b08c856275d2f4343 --- 404.html | 2 +- hashmap.json | 2 +- index.html | 2 +- notes/01_c-basic/01_xdx/index.html | 4 ++-- notes/01_c-basic/02_xdx/index.html | 4 ++-- notes/index.html | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/404.html b/404.html index d24835b..f26fda2 100644 --- a/404.html +++ b/404.html @@ -18,7 +18,7 @@
- + \ No newline at end of file diff --git a/hashmap.json b/hashmap.json index 5938b68..2c6b904 100644 --- a/hashmap.json +++ b/hashmap.json @@ -1 +1 @@ -{"index.md":"uFk6fSzW","notes_index.md":"CdHKXnBk","notes_01_c-basic_02_xdx_index.md":"Cux_q1Jy","notes_01_c-basic_01_xdx_index.md":"DA3nuW_4"} +{"notes_index.md":"CdHKXnBk","notes_01_c-basic_01_xdx_index.md":"DA3nuW_4","notes_01_c-basic_02_xdx_index.md":"Cux_q1Jy","index.md":"uFk6fSzW"} diff --git a/index.html b/index.html index e4e9131..00fcecb 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/01_xdx/index.html b/notes/01_c-basic/01_xdx/index.html index 55f34e8..cd52c9a 100644 --- a/notes/01_c-basic/01_xdx/index.html +++ b/notes/01_c-basic/01_xdx/index.html @@ -20,7 +20,7 @@ -
Skip to content

第一章:计算机组成原理

1.1 计算机系统

  • 计算机(Computer),俗称"电脑",是一种能够接收和存储信息,并按照存储在其内部的程序对海量的数据进行自动、高速的处理,然后将处理结果输出的现代化智能电子设备。
  • 计算机有很多形式,如:台式电脑、笔记本电脑、智能手机、平板电脑等,还有生产环境中提供重要业务支撑的各种服务器。

  • 一个完整的计算机系统硬件(Hardware)系统软件(Software)系统两大部分组成,即:

1.2 冯·诺依曼体系结构

  • 冯·诺依曼是一位多才多艺的科学家,他在数学、物理学、计算机科学、经济学等领域都有杰出的贡献。

  • 冯·诺依曼的主要成就:
    • 在计算机科学领域的最著名贡献是提出了冯·诺依曼体系结构(1946 年),这是现代计算机设计的基础
    • 促进了计算机的可编程性和通用性,使得计算机能够执行各种复杂的任务。
    • 对核武器设计、自动化控制系统、人工智能等领域的发展产生了重要影响。
    • ……

IMPORTANT

冯·诺依曼体系结构是现代计算机(量子计算机除外)设计的基础

  • 冯·诺依曼体系结构的理论要点如下:

    • 存储程序程序指令数据都存储在计算机的内存中,这使得程序可以在运行时修改。

    • 二进制逻辑:所有数据指令都以二进制形式表示。

    • 顺序执行:指令按照它们在内存中的顺序执行,但可以有条件地改变执行顺序。

    • 五大部件:计算机由运算器控制器存储器输入设备输出设备组成。

    • 指令结构:指令由操作码和地址码组成,操作码指示要执行的操作,地址码指示操作数的位置。

    • 中心化控制:计算机的控制单元(CPU)负责解释和执行指令,控制数据流。

NOTE

上述的组件协同工作,构成了一个完整的计算机系统:

  • 运算器控制器通常被集成在一起,组成中央处理器(CPU),负责数据处理和指令执行。
  • 存储器保存数据和程序,是计算机运作的基础。
  • 输入设备输出设备负责与外界的交互,确保用户能够输入信息并接收计算机的处理结果。

1.3 各种硬件处理速度和性能优化

  • 计算机的性能短板:如果 CPU 有每秒处理 1000 个服务请求的能力,各种总线的负载能力能达到 500 个, 但网卡只能接受 200个请求,而硬盘只能负担 150 个的话,那这台服务器得处理能力只能是 150 个请求/ 秒,有 85% 的处理器计算能力浪费了,在计算机系统当中,硬盘的读写速率已经成为影响系统性能进一 步提高的瓶颈。

img

  • 计算机的各个设备部件的延迟从高到低的排列,依次是机械硬盘(HDD)、固态硬盘(SSD)、内存、CPU 。

img

  • 从上图中,我们可以知道,CPU 是最快的,一个时钟周期是 0.3 ns ,内存访问需要 120 ns ,固态硬盘访问需要 50-150 us,传统的硬盘访问需要 1-10 ms,而网络访问是最慢,需要 40 ms 以上。
  • 时间的单位换算如下:
txt
1 秒 = 1000 毫秒,即 1 s = 1000 ms。
+    
Skip to content

第一章:计算机组成原理

1.1 计算机系统

  • 计算机(Computer),俗称"电脑",是一种能够接收和存储信息,并按照存储在其内部的程序对海量的数据进行自动、高速的处理,然后将处理结果输出的现代化智能电子设备。
  • 计算机有很多形式,如:台式电脑、笔记本电脑、智能手机、平板电脑等,还有生产环境中提供重要业务支撑的各种服务器。

  • 一个完整的计算机系统硬件(Hardware)系统软件(Software)系统两大部分组成,即:

1.2 冯·诺依曼体系结构

  • 冯·诺依曼是一位多才多艺的科学家,他在数学、物理学、计算机科学、经济学等领域都有杰出的贡献。

  • 冯·诺依曼的主要成就:
    • 在计算机科学领域的最著名贡献是提出了冯·诺依曼体系结构(1946 年),这是现代计算机设计的基础
    • 促进了计算机的可编程性和通用性,使得计算机能够执行各种复杂的任务。
    • 对核武器设计、自动化控制系统、人工智能等领域的发展产生了重要影响。
    • ……

IMPORTANT

冯·诺依曼体系结构是现代计算机(量子计算机除外)设计的基础

  • 冯·诺依曼体系结构的理论要点如下:

    • 存储程序程序指令数据都存储在计算机的内存中,这使得程序可以在运行时修改。

    • 二进制逻辑:所有数据指令都以二进制形式表示。

    • 顺序执行:指令按照它们在内存中的顺序执行,但可以有条件地改变执行顺序。

    • 五大部件:计算机由运算器控制器存储器输入设备输出设备组成。

    • 指令结构:指令由操作码和地址码组成,操作码指示要执行的操作,地址码指示操作数的位置。

    • 中心化控制:计算机的控制单元(CPU)负责解释和执行指令,控制数据流。

NOTE

上述的组件协同工作,构成了一个完整的计算机系统:

  • 运算器控制器通常被集成在一起,组成中央处理器(CPU),负责数据处理和指令执行。
  • 存储器保存数据和程序,是计算机运作的基础。
  • 输入设备输出设备负责与外界的交互,确保用户能够输入信息并接收计算机的处理结果。

1.3 各种硬件处理速度和性能优化

  • 计算机的性能短板:如果 CPU 有每秒处理 1000 个服务请求的能力,各种总线的负载能力能达到 500 个, 但网卡只能接受 200个请求,而硬盘只能负担 150 个的话,那这台服务器得处理能力只能是 150 个请求/ 秒,有 85% 的处理器计算能力浪费了,在计算机系统当中,硬盘的读写速率已经成为影响系统性能进一 步提高的瓶颈。

img

  • 计算机的各个设备部件的延迟从高到低的排列,依次是机械硬盘(HDD)、固态硬盘(SSD)、内存、CPU 。

img

  • 从上图中,我们可以知道,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 分钟;
@@ -246,7 +246,7 @@
 .idea
 cmake-build-*
 build

7.6 演示

  • 我们可以在项目中,临时创建或复制一个文件,看上述配置是否生效,即:

NOTE

如果是复制并粘贴一个文件到项目中,请点击重新加载 CMake 项目!!!

第八章:C 语言的编译过程(⭐)

8.1 概述

  • C 程序的编译过程,如下所示:

  • 过程 ① :编写(编辑)源代码,即:编写 C 语言源程序代码,并以文件的形式存储在磁盘中。

IMPORTANT

源程序需要以 .c 作为扩展名。

  • 过程 ② :编译,即:将 C 语言源程序转换为目标程序(或目标文件)。如果程序没有错误,没有任何提示,就会生成一个扩展名为 .obj.o 的二进制文件。C 语言中的每条可执行语句经过编译之后,最终都会转换为二进制的机器指令。

IMPORTANT

  • ① 其实,编译阶段包含了预处理编译汇编

  • 预处理是编译过程的第一个阶段。在这个阶段,预处理器处理源代码中的指令(例如:#include#define等),主要任务包括:

    • 头文件包含:将头文件的内容插入到源文件中。例如:#include <stdio.h>会被替换为stdio.h文件的内容。

    • 宏展开:替换宏定义。例如:#define PI 3.14会将代码中的PI替换为3.14

    • 条件编译:根据条件指令(如:#ifdef#ifndef)有选择地编译代码。

    • 删除代码中的注释,但是不会进行语法检查

    • 预处理完成后,生成一个扩展名为.i的中间文件。

  • 编译是将预处理后的源代码转换为汇编代码的过程。在这个阶段,编译器会检查代码的语法和语义,将其转换为目标机器的汇编语言,生成一个扩展名为.s的汇编文件。

  • 汇编是将汇编代码转换为机器代码(也称为目标代码或目标文件)的过程。在这个阶段,汇编器将汇编指令转换为二进制机器指令,生成一个扩展名为.o.obj的目标文件。

  • 过程 ③ :链接(连接),即:将编译形成的目标文件 *.obj*.o和库函数以及其他目录文件链接,形成一个统一的二进制文件 *.exe

IMPORTANT

  • 为什么需要链接库文件?
  • 因为我们的 C 程序会使用 C 程序库中的内容,如:<stdio.h> 中的 printf() 函数,这些函数不是程序员自己写的,而是 C 程序库中提供的,因此需要链接。其实,在链接过程中,还会加入启动代码,这个启动代码(和系统相关,Linux 下主要有 crt0.c、crti.c 等,它们设置堆栈后,再调用 main() 函数)负责初始化程序运行时的环境。
  • 过程 ④ :执行,即:有了可执行的 *.exe文件,我们就可以在控制台上执行运行此 *.exe 文件。

IMPORTANT

如果修改了源代码,还需要重新编译链接,并生成新的 *.exe文件,再执行,方能生效。

8.2 GCC 编译器的介绍

  • 编辑器,如:vim 、vscode 等,是指我们用它来编写源程序的(编辑代码),而我们写的代码语句,电脑是不懂的,我们需要把它转成电脑能懂的语句,编译器就是这样的转化工具。换言之,我们用编辑器编写程序,由编译器编译后才可以运行!
  • 编译器是将易于编写、阅读和维护的高级计算机语言翻译为计算机能解读、运行的低级机器语言的程序。
  • gcc(GNU Compiler Collection,GNU 编译器套件),是由 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 直接生成可执行文件

  • 示例:进行预处理、编译、汇编和链接
shell
gcc HelloWorld.c -o HelloWorld.exe

8.4 通过 gcc 分步编译

8.3.1 概述

  • 预处理命令:
shell
gcc -E 源文件.c -o 源文件.i # 通常以 .i 结尾表示这个文件是一个中间状态
  • 编译(预处理和编译)命令:
shell
gcc -S 源文件.i -o 源文件.s # 在 Linux 中,通常以 .s 结尾;在 Windows 中,通常以 .asm 结尾
  • 汇编(预处理、编译和汇编)命令:
shell
gcc -c 源文件.s -o 源文件.o # 在 Linux 中,通常以 .o 结尾;在 Windows 中,通常以 .obj 结尾
  • 链接(预处理、编译、汇编和链接)命令:
shell
gcc 源文件.o -o 源文件.exe # 在 Linux 中,通常以 .out 结尾;在 Windows 中,通常以 .exe 结尾

8.4.2 应用示例

  • 示例:只进行预处理
shell
gcc -E HelloWorld.c -o HelloWorld.i

  • 示例:只进行预处理和编译
shell
gcc -S HelloWorld.i -o HelloWorld.s

  • 示例:只进行预处理、编译和汇编
shell
gcc -c HelloWorld.s -o HelloWorld.o

  • 示例:进行预处理、编译、汇编和链接
shell
gcc HelloWorld.o -o HelloWorld.exe

Released under the MIT License.

- + \ 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 922862f..274c3d5 100644 --- a/notes/01_c-basic/02_xdx/index.html +++ b/notes/01_c-basic/02_xdx/index.html @@ -20,7 +20,7 @@ -
Skip to content

第一章:变量(⭐)

1.1 程序中变化的数据

  • 在生活中,我们使用最多的不是固定的数据,而是会变化的数据:
    • ① 购物车商品的数量价格等。
    • ② 一首歌播放的时间进度条歌词的展示等。
    • ③ 微信聊天中消息条数时间语音的长度头像名称等。
    • ④ 游戏中技能的冷却时间血量蓝量buff 时间金币的数量等。
    • ……
  • 下图是一个购物车变化数据,即:

  • 那么,在实际开发中,我们就会使用变量保存操作这些变化数据

1.2 变量

  • 变量的定义:变量是程序中不可或缺的组成单位,最基本的存储单元。其实,变量就是一个存储数据的临时空间,可以向其中存储不同类型的数据,如:整数、小数、字符、字符串等,并且变量中的数据在程序运行的时候可以动态改变。

NOTE

  • 变量:用来存储数据容器
  • 数据:可以是一个用来计算的数字,如:上文购物车中的价格等;也可以是一句话中的关键词其它任意格式的数据
  • 变量的特别之处就在于它存放的数据是可以改变的。
  • 我们可以将变量想象为一个容器,盒子中装的就是我们想要的数据,并且我们需要盒子一个特别的名称;通过这个特别的名称,我们可以盒子添加数据移除数据,这个特别的名称就是变量名

NOTE

  • 变量是内存中的一个存储区域,该区域的数据可以在同一类型范围内不断变化
  • ② 通过变量名,可以操作这块内存区域,向其中存储数据获取数据以及移除数据
  • ③ 变量的构成包含三个要素:数据类型变量名需要存储的数据
  • ④ 在生活中,我们会经常说:这件衣服的价格是 100(整型) 元,这双鞋子的价格是 250.5(小数,浮点类型) 元,今天天气真好(字符串类型)之类的话;在计算机科学中,这些都是数据,并且它们是有类型,即:数据类型。(数据类型用于定义变量所能存储的数据的种类以及可以对这些数据进行的操作的一种分类,每种数据类型都有特定的属性和用途,它们决定了变量在内存中如何表示和存储,以及变量可以执行哪些操作)

1.3 变量的声明和使用

  • ① 变量必须先声明,后使用。
  • ② 可以先声明变量再赋值,也可以在声明变量的同时进行赋值。
  • ③ 变量的值可以在同一类型范围内不断变化。

IMPORTANT

在实际开发中,我们通常都会在声明变量的同时,给其赋值,这被称为初始化。

  • 示例:先声明,再使用
c
#include <stdio.h>
+    
Skip to content

第一章:变量(⭐)

1.1 程序中变化的数据

  • 在生活中,我们使用最多的不是固定的数据,而是会变化的数据:
    • ① 购物车商品的数量价格等。
    • ② 一首歌播放的时间进度条歌词的展示等。
    • ③ 微信聊天中消息条数时间语音的长度头像名称等。
    • ④ 游戏中技能的冷却时间血量蓝量buff 时间金币的数量等。
    • ……
  • 下图是一个购物车变化数据,即:

  • 那么,在实际开发中,我们就会使用变量保存操作这些变化数据

1.2 变量

  • 变量的定义:变量是程序中不可或缺的组成单位,最基本的存储单元。其实,变量就是一个存储数据的临时空间,可以向其中存储不同类型的数据,如:整数、小数、字符、字符串等,并且变量中的数据在程序运行的时候可以动态改变。

NOTE

  • 变量:用来存储数据容器
  • 数据:可以是一个用来计算的数字,如:上文购物车中的价格等;也可以是一句话中的关键词其它任意格式的数据
  • 变量的特别之处就在于它存放的数据是可以改变的。
  • 我们可以将变量想象为一个容器,盒子中装的就是我们想要的数据,并且我们需要盒子一个特别的名称;通过这个特别的名称,我们可以盒子添加数据移除数据,这个特别的名称就是变量名

NOTE

  • 变量是内存中的一个存储区域,该区域的数据可以在同一类型范围内不断变化
  • ② 通过变量名,可以操作这块内存区域,向其中存储数据获取数据以及移除数据
  • ③ 变量的构成包含三个要素:数据类型变量名需要存储的数据
  • ④ 在生活中,我们会经常说:这件衣服的价格是 100(整型) 元,这双鞋子的价格是 250.5(小数,浮点类型) 元,今天天气真好(字符串类型)之类的话;在计算机科学中,这些都是数据,并且它们是有类型,即:数据类型。(数据类型用于定义变量所能存储的数据的种类以及可以对这些数据进行的操作的一种分类,每种数据类型都有特定的属性和用途,它们决定了变量在内存中如何表示和存储,以及变量可以执行哪些操作)

1.3 变量的声明和使用

  • ① 变量必须先声明,后使用。
  • ② 可以先声明变量再赋值,也可以在声明变量的同时进行赋值。
  • ③ 变量的值可以在同一类型范围内不断变化。

IMPORTANT

在实际开发中,我们通常都会在声明变量的同时,给其赋值,这被称为初始化。

  • 示例:先声明,再使用
c
#include <stdio.h>
 
 int main() {
 
@@ -227,7 +227,7 @@
 
     return 0;
 }

3.3 进制的转换

3.3.1 概述

  • 不同进制的转换,如下所示:

  • 在计算机中,数据是从右往左的方式排列的;其中,最右边的是低位,最左边的是高位,即:

3.3.2 二进制和十进制的转换

3.3.2.1 二进制转换为十进制

  • 规则:从最低位开始,将每个位上的数提取出来,乘以 2 的 (位数 - 1 )次方,然后求和。

NOTE

  • ① 在学术界,将这种计算规则,称为位权相加法
  • 八进制转换为十进制十六进制转换为十进制二进制转换为十进制的算法相同!!!
  • 示例:十进制转十进制

  • 示例:二进制转十进制

3.3.2.2 十进制转换二进制

  • 规则:将该数不断除以 2 ,直到商为 0 为止,然后将每步得到的余数倒过来,就是对应的二进制。

NOTE

  • ① 在学术界,将这种计算规则,称为短除法连续除2取余法
  • ② 很好理解,只有不断地除以 2 ,就能保证最大的数字不超过 2 ,这不就是二进制(只能有 0 或 1)吗?
  • 八进制转换为二进制十六进制转换为二进制十进制转换为二进制的算法相同!!!
  • 示例:十进制转十进制

  • 示例:十进制转二进制

3.3.3 二进制转八进制

  • 规则:每 3 位二进制就是一个八进制。

  • 示例:011 101 001 -> 351

3.3.4 二进制转十六进制

  • 规则:每 4 位二进制就是一个八进制。

  • 示例:1110 1001 -> 0xE9

3.4 原码、反码和补码

3.4.1 概述

  • 机器数:一个数在计算机的存储形式是二进制,我们称这些二进制数为机器数。机器数可以是有符号的,用机器数的最高位来存放符号位,0 表示正数,1 表示负数。

  • 真值:因为机器数带有符号位,所以机器数的形式值不等于其真实表示的值(真值),以机器数 1000 0001 为例,其真正表示的值(首位是符号位)为 -1,而形式值却是 129 ,因此将带有符号位的机器数的真正表示的值称为机器数的真值。

3.4.2 原码

  • 原码的表示与机器数真值表示的一样,即用第一位表示符号,其余位表示数值。
  • 规则:
    • 正数的原码是它本身对应的二进制数,符号位是 0 。
    • 负数的原码是它本身绝对值对应的二进制数,但是符号位是 1 。
  • +1 的原码,使用 8 位二进数来表示,就是:
十进制数原码(8位二进制数)
+10000 0001
  • -1 的原码,使用 8 位二进数来表示,就是:
十进制数原码(8位二进制数)
-11000 0001

IMPORTANT

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

3.4.3 反码

  • 规则:

    • 正数的反码和它的原码相同。
    • 负数的反码是在其原码的基础上,符号位不变,其余各位取反。
  • +1 的反码,使用 8 位二进数来表示,就是:

十进制数原码(8位二进制数)反码(8位二进制数)
+10000 00010000 0001
  • -1 的反码,使用 8 位二进数来表示,就是:
十进制数原码(8位二进制数)反码(8位二进制数)
-11000 00011111 1110

IMPORTANT

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

3.4.4 补码

  • 规则:

    • 正数的补码和它的原码相同。
    • 负数的补码是在其反码的基础上 + 1 。
  • +1 的补码,使用 8 位二进数来表示,就是:

十进制数原码(8位二进制数)反码(8位二进制数)补码(8位二进制数)
+10000 00010000 00010000 0001
  • -1 的补码,使用 8 位二进数来表示,就是:
十进制数原码(8位二进制数)反码(8位二进制数)补码(8位二进制数)
-11000 00011111 11101111 1111
  • 如果 0 ,按照 +0 的情况进行处理,即:

  • 如果 0 ,按照 -0 的情况进行处理,即:

IMPORTANT

  • ① 补码表示法解决了原码反码存在的两种零(+0-0)的问题,即:在补码表示法中,只有一个零,即 0000 0000。
  • ② 补码使得加法运算减法运算可以统一处理,通过将减法运算转换为加法运算,可以简化硬件设计,提高了运算效率。
  • ③ 计算机底层存储计算的都是二进数的补码

3.4.5 总结

  • ① 正数的原码、反码和补码都是一样的,三码合一。
  • ② 负数的反码是在其原码的基础上,按位取反(0 变 1 ,1 变 0 ),符号位不变;负数的补码是其反码 + 1 。
  • ③ 0 的补码是 0 。

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

  • 如果计算是 2 - 2 ,那么可以转换为 2 + (-2),这样计算机内部在处理减法计算的时候,就会将其转换为加法计算的形式,以简化硬件设计和提高计算效率。
  • 最高位表示符号位,由于符号位的存在,如果使用原码来计算,就会导致计算结果不正确,即:

  • 补码的设计可以巧妙的让符号位也参与计算,并且可以得到正确的计算结果,即:

Released under the MIT License.

- + \ No newline at end of file diff --git a/notes/index.html b/notes/index.html index 73b54a9..f2d7369 100644 --- a/notes/index.html +++ b/notes/index.html @@ -20,8 +20,8 @@ -
Skip to content

计算机基础知识


Released under the MIT License.

- +
Skip to content

计算机基础知识


Released under the MIT License.

+ \ No newline at end of file