Skip to content

Commit

Permalink
小修改
Browse files Browse the repository at this point in the history
  • Loading branch information
VinbeWan committed Aug 10, 2024
2 parents d248280 + d770d89 commit c491739
Show file tree
Hide file tree
Showing 3 changed files with 120 additions and 70 deletions.
19 changes: 19 additions & 0 deletions .github/workflows/m2p.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: main to gh-pages
on:
push:
branches:
- NULL
jobs:
m2p:
runs-on: ubuntu-last
permissions:
contents: write
steps:
- name: Checkout
uses: action/checkout@v4
- name: Merge and Push
run: |
git checkout gh-pages
git merge main -m "sync from branch main"
git push
26 changes: 14 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,20 +35,22 @@ int main(int argc, char* argv[]){
3. 段落和段落之间有一个空行;只换行不换段落,无空行,在前一行结尾加两个空格;
4. **强调** 用 `** **` 标识,*次强调* 用 `* *` 标识,`代码块` 用 `` ` ` `` 标识;
5. 引文和注释用 `>` 标识;书名和文章名用 `*** ***` 标识;
6. `*** ***` `** **` `* *` `` ` ` `` 前后 **各空一个空格**;在中文标点前后的空格可省略;
7. 在中文上下文中用全角标点,比如全角小括号,全角冒号等;
8. 在一个 **术语 (Terminology)** 首次出现的时候在 **半角小括号** 内给出 **对应的外来语**,同时给出 **首字母缩略语 (Acronym)**。这些外来语通常对应 **概念 (Concept)** 的原文 ,希望有助于读者明确分辨词语的含义:
1. 为减少读者的记忆负担,下文分情况使用 **术语的汉语表述** 和 **首字母缩略语**:初始章节以前者为主,进阶章节以后者为主
2. 外来语和缩略语可能视情况在不同章节多次出现
3. 括号外左侧右侧各空一个空格,括号内无空格
4. 外来语不能带斜体,加粗,下划线,删除线和代码块——用默认的字体;
5. 大部分外来语单词摘自 [维基百科](https://zh.wikipedia.org) 和 [C++ 参考手册](https://en.cppreference.com/);
9. **专有名词** 需 **大写**;
10. 图片统一放在 `/images/` 目录下,并采用 **绝对路径** 引入:
6. `*** ***` `** **` `* *` `` ` ` `` 前后 **各空一个空格**,但中文标点前后无需加空格;
7. 中西文字符,或者中文和数字之间加一个空格;
8. 在中文上下文中用全角标点,比如全角小括号,全角冒号等;
9. 要正确使用标点符号,分清 **顿号**、**逗号**、**分号** 和 **句号**,尤其避免一逗到底;
10. 在一个 **术语 (Terminology)** 首次出现的时候在 **半角小括号** 内给出 **对应的外来语**,同时给出 **首字母缩略语 (Acronym)**。这些外来语通常对应 **概念 (Concept)** 的原文 ,希望有助于读者明确分辨词语的含义:
1. 为减少读者的记忆负担,下文分情况使用 **术语的汉语表述** 和 **首字母缩略语**:初始章节以前者为主,进阶章节以后者为主
2. 外来语和缩略语可能视情况在不同章节多次出现
3. 括号外左侧右侧各空一个空格,括号内无空格
4. 外来语 **不能** 带斜体、加粗、下划线、删除线和代码块——用默认的字体;
5. 大部分外来语单词摘自 [维基百科](https://zh.wikipedia.org) 和 [C++ 参考手册](https://en.cppreference.com/);
11. **专有名词** 需 **大写**;
12. 图片统一放在 `/images/` 目录下,并采用 **绝对路径** 引入:
1. 截图统一采用 **PNG** 格式,命名为三位数字,如:`001.png`;
2. 拍照统一采用 **JPEG** 格式,命名为不带前导零的数字,如:`1.jpg`;
11. 在每篇文档结尾写出引用内容的出处;
12. 语言风格:
13. 在每篇文档结尾写出引用内容的出处;
14. 语言风格:
1. 使用 **正式** 的中文白话,尽量 **不用** 口头语;
2. 尽量 **不用** 反问,设问和借喻;
3. 用清晰的修饰限定成分,避免含混不清;不用过于夸张的修饰限定成分;有数据支持的时候要列举数据;
Expand Down
145 changes: 87 additions & 58 deletions 教程/正文/语法和标准库/34_位操作.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,17 @@
### 1.1 计算机中的位

1. 定义:
- 位是 **最小的** 计算机 **数据存储** 单位
- 每一个位存储一个二进制码(记作 **0****1**
2. 对于 **整型** 数据来说,每个计算机位对应这个整数二进制表示中的一个位
3. 8 位构成一个 **字节**,因此 ***在常见的实现中***`int` 类型有 **4** 字节 ( *32* ) `long long`**8** 字节 ( *64* )
4. [ **关于进制** ](/教程/正文/项目/77_关于进制.md)

### 1.2 整数的二进制表示( 以一字节为例 )
1. 无符号:二进制表示中,所有位都用于表示数值,范围在 `0 ~ 255` 之间
2. 有符号:这需要我们好好想一想了
- 也许有符号数最简单的表示方法是使用1位( 最高位 )用于表示符号,其余位用于表示数值本身,但这么做有个问题:`+0``-0` 是两个数,这显然是不合理的,因此,在计算机中,有符号数通常使用 **二进制补码** 来表示(`这也是当今最常用的系统`)
- **二进制补码** 表示法:最高位设置 `0`用后7位表示 `0 ~ 127` 。最高位设置 `1` ,则表示负数,**精髓来了****如何表示负数呢?**
- 位是 **最小的** 计算机 **数据存储** 单位
- 每一个位存储一个二进制码(记作 **0****1**
2. 对于 **整型** 数据来说,每个计算机位对应这个整数二进制表示中的一个位
3. 8 位构成一个 **字节**,因此 ***在常见的实现中***`int` 类型有 **4** 字节*32*`long long`**8** 字节*64*

### 1.2 整数的二进制表示(以一字节为例)

1. 无符号:`unsigned char` 类型,二进制表示中,所有位都用于表示数值,范围在 `0 ~ 255` 之间
2. 有符号:`signed char` 类型:
- 也许有符号数最简单的表示方法是使用 1 位(最高位)用于表示符号,其余位用于表示数值本身,但这么做有个问题:`+0``-0` 是两个数,这显然是不合理的,因此,在计算机中,有符号数通常使用 **二进制补码** 来表示这也是当今最常用的系统
- **二进制补码** 表示法:最高位设置 `0`用后 7 位表示 `0 ~ 127` 。最高位设置 `1` ,则表示负数,具体方法如下:
- 首先,从一个 **9** 位组合 `100000000` 减去一个负数的位组合,结果是该负数的量。例如:有符号数 `100000000` ,其位组合表示一个无符号数 `128` ,因为 `100000000 - 10000000 = 10000000` ,即 `256 - 128 = 128`
- 再由于其最高位为 `1` ,因此,该例的有符号数表示 `-128`
- 以此类推:`10000001` 表示 `-127``10000010` 表示 `-126` ,该方法可以表示 `-128 ~ +127` 的所有整数。
Expand All @@ -24,88 +24,108 @@
## 2. 位操作

> 只能使用 **整型** 数据进行位操作,不能使用 **~~浮点型~~** 数据进行位操作,
> 而一般在 **硬件** 开发上,通常使用 *无符号* 整型,
> 因为 *无符号* 整型没有符号位,可以全部用于表示数值。
>
> 在下面的例子中,使用 **8** 位二进制数来演示。
> 只能使用 **整型** 数据进行位操作,不能使用 ~~**~~浮点型~~**~~ 数据;

### 2.1 位操作的种类

> 下面的例子使用无符号 8 位整数进行演示:
1. 按位与 (&):对应位都为 `1` 时,结果才为 `1`

```C
(10011010) & (10110110) // 表达式
10010010 // 结果值
```

当然 **C** 中有一个按位与和赋值结合的运算符:`&=`
2. 按位或 (|):对应位只要有一个为 `1` 或都为 `1` ,结果就为 `1`:

```C
(10011010) | (10110110) // 表达式
10111110 // 结果值
```

当然 **C** 中也有一个按位或和赋值结合的运算符:`|=`
3. 按位异或 (^):对应位不同时,结果为 `1`:

```C
(10011010) ^ (10110110) // 表达式
00101100 // 结果值
```

当然 **C** 中也有一个按位异或和赋值结合的运算符:`^=`
4. 按位取反 (~):`1` 变 `0` ,`0` 变 `1` :

```C
~(10011010) // 表达式
01100101 // 结果值
```

5. 按位左移 (<<):

```C
(10011010) << 2 // 表达式
01101000 // 结果值
```

当然 **C** 中也有一个按位左移和赋值结合的运算符:`<<=`
6. 按位右移 (>>):

```C
(10011010) >> 2 // 表达式,有符号
00100110 // 在某些系统的结果值
11100110 // 在另一些些系统的结果值
00100110 // 在某些实现中的结果
11100110 // 在另一些实现中的结果
```
这是由于在不同系统上,对有符号数的右移操作,其左端填补数可以为 `1` 也可以为 `0` ,因此,**建议** 在右移操作时,使用无符号数

在不同实现中,对有符号数的右移操作,其左端填补数可以为 `1` 也可以为 `0`。大多数实现中,左端填补数和原符号位相同,确保正负不变。

```C
(10011010) >> 2 // 表达式,无符号
00100110 // 结果值
```

当然 **C** 中也有一个按位右移和赋值结合的运算符:`>>=`

### 2.2 位操作的应用

> 注:在之后的实际项目里,尤其是对 **硬件** 开发上,位操作会经常用到
>
> 在下面的示例中,使用无符号整数来演示,即`unsigned int` 类型,默认你们已经引入 `stdint.h` 头文件:
> ```C
> include <stdint.h>
> ```
> 或者,也可以使用 `typedef` 定义一个无符号整数类型,如下:
> ```C
> typedef unsigned int uint_t;
> ```
>
> 当然你会看到,在示例中我的 **二进制字面量** 只有 **8** 位, 这其实没什么问题,变量的二进制位数是由类型决定的,
> 而不是字面量的位数,因此, **字面量位数** 可以比 **该字面量类型位数** 少,也可以比 **该字面量类型位数** 多,
> 但需要注意的是,二进制存储是 **从右往左** 的,因此,如果 **字面量位数** 比 **该字面量类型的位数** 多,那么,字面量左边的位会被丢弃,如下:
> ```C
> uint_t flag = 0b1111111100000000000000000000000000000000; // 40位的字面量,假设int为32位,那么flag的存储类型只有32二进制位
> // flag = 0b00000000000000000000000000000000, flag最左的8位被丢弃
> ```
> 若是字面量位数比该字面量类型的位数少,那么,字面量左边的位会被补零。

1. **掩码** ( **MASK** )

```C
#include <stdint.h>
```

或者,也可以使用 `typedef` 定义一个无符号整数类型,如下:

```C
typedef unsigned int uint_t;
```

示例中的 **二进制字面量** 只有 **8** 位,这其实没什么问题,因为二进制位数是由类型决定的,而不是字面量的位数,因此,**字面量位数** 可以比 **该字面量类型位数** 少,也可以比 **该字面量类型位数** 多。但需要注意的是,二进制存储是 **从右往左** 的,因此,如果 **字面量位数****该字面量类型的位数** 多,那么,字面量左边的位会被丢弃,如下:

```C
uint_t flag = 0b1111111100000000000000000000000000000000;
// 40位的字面量,如果 int 为 32 位,那么 flag 只能存储 32 个二进制位

// 可能造成如下结果:
// flag = 0b00000000000000000000000000000000(flag 最左的 8 位被丢弃)
```

若是字面量位数比该字面量类型的位数少,那么,字面量左边的位会被补零。

1. **掩码** ( **MASK** )
- 定义:掩码是一个 **二进制数**,用于 **屏蔽** 另一个二进制数的特定位
- 可以这样类比:掩码就像一个 **滤网** ,只有掩码中的 *1* 是孔,把flag的对应位置给透出来,其余位置被 *0* 给堵上
- 下面举个简单的栗子:
- 下面举个简单的例子:

```C
uint_t flag = 0b10101010;
typedef unsigned char ubyte;

ubyte flag = 0b10101010;

//定义MASK,0号位为1,其余位为0
uint_t mask = 0b00000010;
ubyte mask = 0b00000010;

//掩码操作
flag = flag & mask; //此时 flag = 0b00000010
Expand All @@ -114,42 +134,51 @@
2. **打开位** ( **SET** )
- 定义:打开位,就是将特定位设置为 `1`,同时保持其它位不变
- 使用 `|` 运算符和掩码,翻译成人话就是:任何位和 `1` 组合,结果都是 `1`;任何位和 `0` 组合,结果都是该位本身
- 以上一节的 **mask** ( 只有`1`号位为1 ) 为例:
- 以上一节的 **mask**(只有 `1` 号位为 1)为例:

```C
uint_t flag = 0b10101001;
ubyte flag = 0b10101001;
flag |= mask; //此时 flag = 0b10101011
```

根据 **mask** 中为 `1` 的位, **flag** 中对应位设置为 `1` ,其余位不变

3. **清空位** ( **CLEAR** )
- 定义:清空位,就是将特定位设置为 `0`, 同时保持其它位不变
- 使用 `&` 和 `~` 运算符与掩码,翻译成人话就是:~~翻译不出人话~~,看代码吧
- 以上一节的 **mask** ( 只有`1`号位为1 ) 为例:
```C
uint_t flag = 0b10101011;
- 使用 `&` 和 `~` 运算符与掩码,看代码:
- 以上一节的 **mask**(只有 `1` 号位为 1)为例:

```C
ubyte flag = 0b10101011;
flag &= ~mask; //此时 flag = 0b10101001
```

根据 **mask** 中为 `1` 的位, **flag** 中对应位设置为 `0` ,其余位不变

4. **切换位** ( **TOGGLE** )
- 定义:切换位,就是将特定位取反,同时保持其它位不变
- 使用 `^` 运算符和掩码,翻译成人话就是:任何位和 `1` 组合,结果都是该位取反;任何位和 `0` 组合,结果都是该位本身
- 以新的 **mask** ( `0b11110000` ) 为例:
```C
uint_t flag = 0b10101011;
- 使用 `^` 运算符和掩码,即:任何位和 `1` 组合,结果都是该位取反;任何位和 `0` 组合,结果都是该位本身
- 以新的 **mask**(`0b11110000`)为例:

```C
ubyte flag = 0b10101011;
flag ^= mask; //此时 flag = 0b01011011
```

根据 **mask** 中为 `1` 的位, **flag** 中对应位切换,其余位不变

5. **读取位** ( **READ** )
- 定义:读取位,就是只读取特定位的值
- 使用 `&` 运算符和掩码,翻译成人话就是:~~翻译不出人话~~,看代码吧
- 以上一节的 **mask** ( 只有`1`号位为1 ) 为例:
```C
- 使用 `&` 运算符和掩码,代码如下:
- 以上一节的 **mask**(只有 `1` 号位为 1)为例:

```C
//typedef unsigned int uint_t;

uint_t flag = 0b10101011;
if ((flag & mask) == mask) {
printf("1号位为1.");
printf("1号位为1");
}
```
根据 **mask** 中为 `1` 的位, 在**flag** 中只读对应.

根据 **mask** 中为 `1` 的位, 在 **flag** 中只读对应。

0 comments on commit c491739

Please sign in to comment.