owned this note
owned this note
Published
Linked with GitHub
# 2021q1 Homework2 (quiz2)
contributed by < `yellow-hank` >
###### tags: `LinuxKernel`
## 測驗 `1`
```cpp
#include <string.h>
typedef struct __element {
char *value;
struct __element *next;
struct list_head list;
} list_ele_t;
typedef struct {
list_ele_t *head; /* Linked list of elements */
list_ele_t *tail;
size_t size;
struct list_head list;
} queue_t;
static list_ele_t *get_middle(struct list_head *list)
{
struct list_head *fast = list->next, *slow;
list_for_each (slow, list) {
if (fast->next == list || fast->next->next == list)
break;
fast = fast->next->next;
}
return list_entry(slow, list_ele_t, list);
}
static void list_merge(struct list_head *lhs,
struct list_head *rhs,
struct list_head *head)
{
INIT_LIST_HEAD(head);
if (list_empty(lhs)) {
list_splice_tail(lhs, head);
return;
}
if (list_empty(rhs)) {
list_splice_tail(rhs, head);
return;
}
while (!list_empty(lhs) && !list_empty(rhs)) {
char *lv = list_entry(lhs->next, list_ele_t, list)->value;
char *rv = list_entry(rhs->next, list_ele_t, list)->value;
struct list_head *tmp = strcmp(lv, rv) <= 0 ? lhs->next : rhs->next;
list_del(tmp);
list_add_tail(tmp, head);
}
list_splice_tail(list_empty(lhs) ? rhs : lhs, head);
}
void list_merge_sort(queue_t *q)
{
if (list_is_singular(&q->list))
return;
queue_t left;
struct list_head sorted;
INIT_LIST_HEAD(&left.list);
list_cut_position(&left.list, &q->list, &get_middle(&q->list)->list);
list_merge_sort(&left);
list_merge_sort(q);
list_merge(&left.list, &q->list, &sorted);
INIT_LIST_HEAD(&q->list);
list_splice_tail(&sorted, &q->list);
}
```
### 解釋原理
Merge sort 先檢查 list 是否只有一個值,若只有一個則不進行排序,直接回傳。 Merge sort 是先分割,在合併時做排序。而 quick sort 是在分割時,進行排序,合併時直接將排序好的合併。
```cpp
INIT_LIST_HEAD(&left.list);
```
上述會先初始化一個 double linked list
```cpp
list_cut_position(&left.list, &q->list, &get_middle(&q->list)->list);
```
示意圖
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct4 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct5 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4:f1 -> struct3;
struct5:f1 -> struct4;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct3:f2 -> struct4;
struct4:f2 -> struct5;
struct5:f2 -> struct0:f0;
struct0:f1 -> struct5
struct0:f2 -> struct1:f0;
}
```
list_cut_position 會從 middle 切割成兩個 doubly-linked list
`&q->list` 分割後部分
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct0:f2 -> struct1:f0;
struct3:f2 -> struct0;
struct0:f1 -> struct3;
}
```
&left.list 分割部分
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct1:f2 -> struct2;
struct2:f2 -> struct0;
struct0:f2 -> struct1:f0;
struct0:f1 -> struct2;
}
```
說明 `get_middle`
```cpp
get_middle(&q->list)
```
初始化 fast 指向下一個 node, slow 指向 list 的開頭
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct4 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct5 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct6 [label="slow"];
struct7 [label="fast"];
struct6 -> struct0;
struct7 -> struct1;
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4:f1 -> struct3;
struct5:f1 -> struct4;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct3:f2 -> struct4;
struct4:f2 -> struct5;
struct5:f2 -> struct0:f0;
struct0:f1 -> struct5;
struct0:f2 -> struct1:f0;
}
```
接下來移動 slow 至下一個節點, fast 移動兩個節點
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct4 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct5 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct6 [label="slow"];
struct7 [label="fast"];
struct6 -> struct1;
struct7 -> struct3;
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4:f1 -> struct3;
struct5:f1 -> struct4;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct3:f2 -> struct4;
struct4:f2 -> struct5;
struct5:f2 -> struct0:f0;
struct0:f1 -> struct5;
struct0:f2 -> struct1:f0;
}
```
:::warning
避免說「一步」這樣不精準的話,走訪的過程中,你可以移動「一個節點」或數個。
:notes: jserv
:::
接下來移動 slow 至下一個節點, fast 移動兩個節點
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct4 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct5 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct6 [label="slow"];
struct7 [label="fast"];
struct6 -> struct2;
struct7 -> struct5;
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4:f1 -> struct3;
struct5:f1 -> struct4;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct3:f2 -> struct4;
struct4:f2 -> struct5;
struct5:f2 -> struct0:f0;
struct0:f1 -> struct5;
struct0:f2 -> struct1:f0;
}
```
當 fast 接下來走到原本的開頭,slow 會是 list 的中間點。
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct4 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct5 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct6 [label="slow"];
struct7 [label="fast"];
struct6 -> struct3;
struct7 -> struct0;
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4:f1 -> struct3;
struct5:f1 -> struct4;
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct3:f2 -> struct4;
struct4:f2 -> struct5;
struct5:f2 -> struct0:f0;
struct0:f1 -> struct5;
struct0:f2 -> struct1:f0;
}
```
獲得中間的 node ,由 slow 指向著,回傳 slow 。
```cpp
list_merge_sort(&left);
list_merge_sort(q);
```
再一次呼叫 merge sort 排序 &left 和 q 。
```cpp
list_merge(&left.list, &q->list, &sorted);
```
此函式會合併 `&left.list` 和 `&q->list`,並且將結果存入 sorted
下圖會舉例由小排到大
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 2|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 3|{<f1>prev|<f2>next}}"];
struct3 [label="{<f0> 5|{<f1>prev|<f2>next}}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct4 [label="{lhs}"];
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct3:f1 -> struct2;
struct4 -> struct0
struct1:f2 -> struct2;
struct2:f2 -> struct3;
struct0:f2 -> struct1:f0;
struct3:f2 -> struct0;
struct0:f1 -> struct3;
}
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{<f0> 1|{<f1>prev|<f2>next}}"];
struct2 [label="{<f0> 4|{<f1>prev|<f2>next}}"];
struct4 [label="{rhs}"];
struct0 [label="{{<f1>prev|<f2>next}}"];
struct4 -> struct0;
struct1:f1 -> struct0;
struct2:f1 -> struct1;
struct1:f2 -> struct2;
struct2:f2 -> struct0;
struct0:f2 -> struct1:f0;
struct0:f1 -> struct2;
}
```
接下來會各自比較 lhs 和 rhs 的第一個值,將較小的值放入 sorted 裡面
```graphviz
digraph structs {
node[shape=record]
struct0 [label="sorted"];
struct1 [label="{{<f1>prev|<f2>next}}"];
struct2 [label="{1|{<f1>prev|<f2>next}}"];
struct0 -> struct1;
struct1:f2 -> struct2;
struct2:f2 -> struct1;
struct1:f1 -> struct2;
struct2:f1 -> struct1;
}
```
然後將指向比較小的指標移動到下一個,接續重複上述動作,直到 lhs 或 rhs 其中一個為空。將不為空的那一部分直接接到 sorted 後面,完成一次合併,合併完後是一個排序好的 doubly-linked list。
```cpp
INIT_LIST_HEAD(&q->list);
list_splice_tail(&sorted, &q->list);
```
初始化一個 doubly-linked list ,把排序好的 sorted 放到queue 的 list 中。
---
## 測驗 `2`
考慮函式 func 接受一個 16 位元無號整數 N,並回傳小於或等於 N 的 power-of-2
```cpp
uint16_t func(uint16_t N) {
/* change all right side bits to 1 */
N |= N >> 1;
N |= N >> 2;
N |= N >> 4;
N |= N >> 8;
return (N + 1) >> 1;
}
```
假定 N = 10101~2~ = 21~10~,那麼 func(21) 要得到 16,請補完程式碼,使其運作符合預期。
### 解釋原理
要回傳小於或等於 N 的 power-of-2 ,先分成兩個部分,一個是 N = 0 和 N > 0。
#### N = 0
N = 0 轉換成二進位為 0000 0000 0000 0000~2~,可以看到上述的 bit 皆為0,所以不論怎麼位移,再和自己做 bitwise OR ,結果皆為零。
#### N > 0
N > 0 意味著在16個 bits 中可以找到一最高的位元值為1,只要把低於他的 bit 設為1,加1後,再往右位移1位,就能找到小於或等於 N 的 power-of-2。
假設第k位為N的最高 bit 值為1,
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{0|0|0|0|0|0|<f0> 1|?|?|?|?|?|?|?|?|?}}"];
struct2[label="kth bit"];
struct2 -> struct1:f0
}
```
set bit 的 bitwise operation 寫法如下:
```cpp
N |= 1 << k; //set kth position to 1
```
因為最大為 16 bits,可以逐一設定 k 以下的值為 1 ,直接引用 N 中位元為 1 ,且位置最高的當作 set bit bitwise operation 的 1 。需要考慮最高位元為 16 ,所以你可以這樣寫:
```cpp
N |= N >> 1;
N |= N >> 2;
N |= N >> 3;
N |= N >> 4;
N |= N >> 5;
N |= N >> 6;
N |= N >> 7;
N |= N >> 8;
N |= N >> 9;
N |= N >> 10;
N |= N >> 11;
N |= N >> 12;
N |= N >> 13;
N |= N >> 14;
N |= N >> 15;
```
但是這樣效率太差,可以思考位移一次,和自己做一次 OR 會產生二倍的 1 ,最大是要產生 15 個 1,最少要做四次才能達到 15 的目標,下列是效率較好的程式碼:
```cpp
N |= N >> 1;
N |= N >> 2;
N |= N >> 4;
N |= N >> 8;
```
做完結果如下:
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{0|0|0|0|0|0|<f0> 1|1|1|1|1|1|1|1|1|1}}"];
struct2[label="kth bit"];
struct2 -> struct1:f0
}
```
```cpp
(N + 1) >> 1;
```
N + 1 後結果如下:
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{0|0|0|0|0|1|<f0> 0|0|0|0|0|0|0|0|0|0}}"];
struct2[label="kth bit"];
struct2 -> struct1:f0
}
```
往右位移一位
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{0|0|0|0|0|0|<f0> 1|0|0|0|0|0|0|0|0|0}}"];
struct2[label="kth bit"];
struct2 -> struct1:f0
}
```
得到在第 k 位值為 1 ,其餘皆為 0 的數,符合題目的小於或等於 N 的 power-of-2。
---
## 測驗 `3`
`bitcpy` 實作程式碼:
```cpp
#include <stdint.h>
void bitcpy(void *_dest, /* Address of the buffer to write to */
size_t _write, /* Bit offset to start writing to */
const void *_src, /* Address of the buffer to read from */
size_t _read, /* Bit offset to start reading from */
size_t count)
{
size_t read_lhs = _read & 7;
size_t read_rhs = 8 - read_lhs;
const uint8_t *source = (const uint8_t *) _src + (_read / 8);
size_t write_lhs = _write & 7;
size_t write_rhs = 8 - write_lhs;
uint8_t *dest = (uint8_t *) _dest + (_write / 8);
static const uint8_t read_mask[] = {
0x00, /* == 0 00000000b */
0x80, /* == 1 10000000b */
0xC0, /* == 2 11000000b */
0xE0, /* == 3 11100000b */
0xF0, /* == 4 11110000b */
0xF8, /* == 5 11111000b */
0xFC, /* == 6 11111100b */
0xFE, /* == 7 11111110b */
0xFF /* == 8 11111111b */
};
static const uint8_t write_mask[] = {
0xFF, /* == 0 11111111b */
0x7F, /* == 1 01111111b */
0x3F, /* == 2 00111111b */
0x1F, /* == 3 00011111b */
0x0F, /* == 4 00001111b */
0x07, /* == 5 00000111b */
0x03, /* == 6 00000011b */
0x01, /* == 7 00000001b */
0x00 /* == 8 00000000b */
};
while (count > 0) {
uint8_t data = *source++;
size_t bitsize = (count > 8) ? 8 : count;
if (read_lhs > 0) {
data <<= read_lhs;
if (bitsize > read_rhs)
data |= (*source >> read_rhs);
}
if (bitsize < 8)
data &= read_mask[bitsize];
uint8_t original = *dest;
uint8_t mask = read_mask[write_lhs];
if (bitsize > write_rhs) {
/* Cross multiple bytes */
*dest++ = (original & mask) | (data >> write_lhs);
original = *dest & write_mask[bitsize - write_rhs];
*dest = original | (data << write_rhs);
} else {
// Since write_lhs + bitsize is never >= 8, no out-of-bound access.
mask |= write_mask[write_lhs + bitsize];
*dest++ = (original & mask) | (data >> write_lhs);
}
count -= bitsize;
}
}
```
### 解釋原理
```cpp
size_t read_lhs = _read & 7;
```
一個 byte 有 8 個 bits ,需要從 _read 中得到從第幾個 byte 第幾個 bit 開始讀取。
```cpp=
_read / 8;
```
上述可以獲得在第幾個 byte
```cpp=
_read % 8;
```
上述可以獲得在第幾個 bit,上述的方式可以是改寫成更有效率的方式,因為 8 是 2 的 3 次方,所以可以藉由 bitwise operation 中的 and operation 獲得最低的 3 個 bit,得到下列的方式實作。
```cpp=
_read & 7;
```
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{?|?|?|?|?|?|?|?}}"];
}
```
做 and operation
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{0|0|0|0|0|1|1|1}}"];
}
```
會得到以下結果,跟取餘數是一樣。
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{0|0|0|0|0|?|?|?}}"];
}
```
接下來移動 source 到要存取的 byte 中,如下列程式碼
```cpp
const uint8_t *source = (const uint8_t *) _src + (_read / 8);
```
write 的部分使用跟上述 read 一樣的方式移動到要寫入的 bit 位置
```cpp
size_t write_lhs = _write & 7;
size_t write_rhs = 8 - write_lhs;
uint8_t *dest = (uint8_t *) _dest + (_write / 8);
```
下列為設定要一次從最高位取走幾個 bit 的 mask。
```cpp
static const uint8_t read_mask[] = {
0x00, /* == 0 00000000b */
0x80, /* == 1 10000000b */
0xC0, /* == 2 11000000b */
0xE0, /* == 3 11100000b */
0xF0, /* == 4 11110000b */
0xF8, /* == 5 11111000b */
0xFC, /* == 6 11111100b */
0xFE, /* == 7 11111110b */
0xFF /* == 8 11111111b */
};
```
下列為設定要一次從最高位清空幾個 bit 的 mask。
```cpp
static const uint8_t write_mask[] = {
0xFF, /* == 0 11111111b */
0x7F, /* == 1 01111111b */
0x3F, /* == 2 00111111b */
0x1F, /* == 3 00011111b */
0x0F, /* == 4 00001111b */
0x07, /* == 5 00000111b */
0x03, /* == 6 00000011b */
0x01, /* == 7 00000001b */
0x00 /* == 8 00000000b */
};
```
此處的迴圈只能一次最高能處理 8 bits 的複製
```cpp
while (count > 0) {
uint8_t data = *source++;
size_t bitsize = (count > 8) ? 8 : count;
if (read_lhs > 0) {
data <<= read_lhs;
if (bitsize > read_rhs)
data |= (*source >> read_rhs);
}
if (bitsize < 8)
data &= read_mask[bitsize];
uint8_t original = *dest;
uint8_t mask = read_mask[write_lhs];
if (bitsize > write_rhs) {
/* Cross multiple bytes */
*dest++ = (original & mask) | (data >> write_lhs);
original = *dest & write_mask[bitsize - write_rhs];
*dest = original | (data << write_rhs);
} else {
// Since write_lhs + bitsize is never >= 8, no out-of-bound access.
mask |= write_mask[write_lhs + bitsize];
*dest++ = (original & mask) | (data >> write_lhs);
}
count -= bitsize;
}
```
記憶體排序是根據下圖所示
![](https://i.imgur.com/WpjBDuk.jpg)
```cpp
if (read_lhs > 0) {
data <<= read_lhs;
if (bitsize > read_rhs)
data |= (*source >> read_rhs);
}
```
read_lhs > 0 代表著取的資料不是從每個 bytes 的最高位開始取,所以需要藉由位移來將資料放入 data 中,下圖表示 data 的資料分成兩部份 lhs 和 rhs 的部分。rhs 的部分會透過 bitsize > read_rhs 來判斷當 bitsize 大過 lhs 的個數 =(8 - read_lhs)= read_rhs ,需要到下一個 bytes 取得 rhs 的部分。
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{<f0>?|?|?|<f1>?|<f2>?|?|?|<f3>?}}"];
struct2 [label="{lhs}"];
struct3 [label="{rhs}"];
struct2 -> struct1:f0;
struct2 -> struct1:f1;
struct3 -> struct1:f2;
struct3 -> struct1:f3;
}
```
```cpp
if (bitsize < 8)
data &= read_mask[bitsize];
```
如果單次取的 bit 個數少於 8 時,需要透過上述設定移除不需要的資料
data 的資料
```graphviz
digraph structs {
node[shape=record]
struct1 [label="{{?|?|?|?|?|?|?|?}}"];
}
```
和 read_mask 做 and operation 移除不需要的資料
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{1|1|1|0|0|0|0|0}}"];
}
```
會得到以下結果,保留需要的資料。
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|0|0|0|0|0}}"];
}
```
```cpp
uint8_t original = *dest;
uint8_t mask = read_mask[write_lhs];
```
先設定好目的地的資料,和需要用來清空特定部分 bit 的 mask
```cpp
if (bitsize > write_rhs) {
/* Cross multiple bytes */
*dest++ = (original & mask) | (data >> write_lhs);
original = *dest & write_mask[bitsize - write_rhs];
*dest = original | (data << write_rhs);
} else {
// Since write_lhs + bitsize is never >= 8, no out-of-bound access.
mask |= write_mask[write_lhs + bitsize];
*dest++ = (original & mask) | (data >> write_lhs);
}
```
這裡分成兩個部分,一個是需要橫跨兩個 bytes 的操作,另一個只有在一個 byte 內完成,當 bitsize > write_rhs (= write_lhs 的個數) 時,需要進行兩個 bytes 的操作。
```cpp
*dest++ = (original & mask) | (data >> write_lhs);
```
這是 data 中的值
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|0|0|0|0|0}}"];
}
```
藉由移動到 LSB 符合記憶體排序的方式
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{0|0|0|0|0|?|?|?}}"];
}
```
original 的原始值
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|?|?|?|?|?}}"];
}
```
mask 的值
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{1|1|1|1|1|0|0|0}}"];
}
```
透過和 mask 做 bitwise and operation 清空特定的位置,得到下列結果
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|?|?|0|0|0}}"];
}
```
跟上述位移過的 data 進行合併
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{0|0|0|0|0|?|?|?}}"];
}
```
做 bitwise or operation
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|?|?|0|0|0}}"];
}
```
得到下列結果,完成第一個 byte 的複製
```graphviz
digraph structs {
node[shape=record]
struct2 [label="{{?|?|?|?|?|<f0>?|?|<f1>?}}"];
struct3 [label="new data"];
struct3 -> struct2:f0;
struct3 -> struct2:f1;
}
```
```cpp
original = *dest & write_mask[bitsize - write_rhs];
```
將第二個 byte 需要清空的地方移除,bitsize-write_rhs(=lhs的個數),是需要放入的個數
```cpp
*dest = original | (data << write_rhs);
```
將資料放入到第二個 byte 中,完成橫跨兩個的 bytes 的複製
接下來探討一個 byte 內的複製
```cpp
mask |= write_mask[write_lhs + bitsize];
*dest++ = (original & mask) | (data >> write_lhs);
```
原本的 mask 放著要從 lhs 開始清空的位置,但是是直接清空到位置 0 的部分,有機會會額外移除資料,需要透過 write_mask[write_lhs + bitsize] 來設定停止點,write_lhs + bitsize 代表著從 lhs 加上要複製的個數(bitsize) 為停止的位置。最後透過與上述相同的方式複製到目的地中。
```cpp
count -= bitsize;
```
減去這次處理 bit 個數,以便迴圈檢查是否完成當初 count 設定需要複製 bit 的個數。
---
## 測驗 `4`