---
tags: Linux Kernal
---
# 2023q1 Homework5 (assessment)
contributed by < [POCHUN-CHEN](https://github.com/POCHUN-CHEN) >
> [L08: assessment](https://hackmd.io/@sysprog/r1O7Xcp12)
# 專案與作業
## lab0-c
1. 有把 Git 方面的講義看完,對於版本控制有更多的知識,之後會更加注意 Commit 撰寫。
2. 在編碼方式有做了不少努力,除了成大 wiki 上的講義,也有看了 CSAPP 第二章後面的部份題目。
3. 加強對於指標與 linked list 的知識與應用,之前在撰寫 lab0-c 很多都是霧裡看花,雖然讀完講義後懂的東西更多,但目前也知道我還沒真的懂(還無法對於程式碼的缺失進行改進)。
4. 預計會持續盡力完成 lab0-c 之作業要求。
:::info
在講義[`mergeTwoLists()`](https://hackmd.io/@sysprog/c-linked-list#%E6%A1%88%E4%BE%8B%E6%8E%A2%E8%A8%8E-LeetCode-21-Merge-Two-Sorted-Lists)中,
```c=
struct ListNode *mergeTwoLists(struct ListNode *L1, struct ListNode *L2) {
struct ListNode *head = NULL, **ptr = &head, **node;
for (node = NULL; L1 && L2; *node = (*node)->next) {
node = (L1->val < L2->val) ? &L1: &L2;
*ptr = *node;
ptr = &(*ptr)->next;
}
*ptr = (struct ListNode *)((uintptr_t) L1 | (uintptr_t) L2);
return head;
}
```
第 4 行的 `*node = (*node)->next` 左右式的資料型別是不同的,`struct ListNode` 應改成 `struct list_head` ,之後再使用 `element_t *L1_entry = list_entry(L1, element_t, list);` 取得內含值結構體 `element_t` 的參數 `L1_entry` 方便比較大小排序。
:::
## fibdrv
在寫大數的時候發現困難重重,經過與老師一對一討論後,詳讀前三週課程(目前看到第二週),之前的疑問有很多都知道該如何處理(但實做後才能驗證自己是否掌握)。預計看完第三週講義後,會進入 fibdrv 實做。
## quiz
## 目前學習模式
# 課堂問題
1. 在[運用 bit-wise operator](https://hackmd.io/@sysprog/c-numerics#運用-bit-wise-operator)中,
* C 語言中,`x & (x - 1) == 0` 的數學意義
* power of two :代表上式能檢查 $2^n$
* signed v.s. unsigned :有無號如何跟上式有關係呢?
:::info
`x & (x - 1)` 運算後的結果是把二進位的最右面那個 `1` 變成 `0` ,除了可以檢查二進位數值中有幾個 `1` 位元、檢查是否為 $2^n$,還有沒有更深層的理解呢?
signed v.s. unsigned :有無號如何跟上式有關係呢?
:::
2. 在[Integer Overflow 案例分析](https://hackmd.io/@sysprog/c-numerics#Integer-Overflow-案例分析)的 2002 年 FreeBSD [53]例子中,把「負」的數值作為 maxlen 帶入,由於 `memcpy(user_dest, kbuf, len);` ,`len` 是 unsigned ,故該「負」的數值,會表示成一個很大的正數值,在此刻,輸入參數就會是錯誤的,導致記憶體位置錯誤。
:::info
為什麼強調「負」的數值,如果是錯誤的`len` 數值,應該就會導致輸入參數會是錯誤,導致程式有問題。況且原文中提到「懷有惡意的程式設計師」,是否不只是程式錯誤的問題?還會引發更嚴重的問題呢?(例如可以存取到特定的記憶體位置內部的資料)
:::
3. 在 [跟你想像不同的 struct](https://hackmd.io/odsx15lMRDiqsuQDL8LE8g?view#%E8%B7%9F%E4%BD%A0%E6%83%B3%E5%83%8F%E4%B8%8D%E5%90%8C%E7%9A%84-struct) 中, `&((TYPE *)0)->MEMBER` 把地址 0 轉形成函式指標,利用 0 指到 `MEMBER` 的大小當成 offset 的值。
:::info
編譯器處理 `&((TYPE *)0)->MEMBER` 時,不會真正去存取地址為 0 的記憶體區段,那背後到底是如何運作(都不真的 0 了)?
:::
4. 在[Linked list 在 Linux 核心原始程式碼](https://hackmd.io/@sysprog/c-linked-list#Linked-list-%E5%9C%A8-Linux-%E6%A0%B8%E5%BF%83%E5%8E%9F%E5%A7%8B%E7%A8%8B%E5%BC%8F%E7%A2%BC)、[應用案例: 雙向環狀鏈結串列](https://hackmd.io/@sysprog/linux-macro-containerof#%E6%87%89%E7%94%A8%E6%A1%88%E4%BE%8B-%E9%9B%99%E5%90%91%E7%92%B0%E7%8B%80%E9%8F%88%E7%B5%90%E4%B8%B2%E5%88%97)之中(兩者內容一致),對於 `list_for_each` 的程式碼定義與圖示如下
```c
#define list_for_each(node, head) \
for (node = (head)->next; node != (head); node = node->next)
```
```graphviz
digraph ele_list {
rankdir=LR;
node[shape=record];
h [label="head", style=dashed, color=grey];
h -> e1:right:w [style=dashed, color=grey];
e1 [label="head node|{<left>prev|<right>next}", style="bold", color=grey];
e2 [label="cat|{<left>prev|<right>next}", style="bold"];
e3 [label="...", style="bold"];
e4 [label="eat|{<left>prev|<right>next}", style="bold"];
e5 [label="fat|{<left>prev|<right>next}", style="bold"];
e1:right:e -> e2:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e2:right:e -> e3:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e3:right:e -> e4:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e4:right:e -> e5:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e5:right:e -> e1:left:w[arrowhead=normal, arrowtail=normal, dir=both];
}
```
:::info
是否應為下圖才比較合理?
```graphviz
digraph ele_list {
rankdir=LR;
node[shape=record];
h [label="head", style=dashed, color=grey];
e1 [label="head node|{<left>prev|<right>next}", style="bold", color=grey];
e2 [label="cat|{<left>prev|<right>next}", style="bold"];
e3 [label="...", style="bold"];
e4 [label="eat|{<left>prev|<right>next}", style="bold"];
e5 [label="fat|{<left>prev|<right>next}", style="bold"];
h -> e1:left:w [style=dashed, color=grey, dir=both];
e1:right:e -> e2:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e2:right:e -> e3:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e3:right:e -> e4:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e4:right:e -> e5:left:w[arrowhead=normal, arrowtail=normal, dir=both];
e5:right:e -> h:w[arrowhead=normal, arrowtail=normal, dir=both, weight = 15];
}
```
:::
5. 在[list_entry](https://hackmd.io/@sysprog/c-linked-list#list_entry)中提到,
>這時可以查詢到 `list_entry` 是 `container_of` 等價的包裝,符合以 list_ 開頭的命名慣例,此處的 entry 就是 list 內部的節點。
**特別注意:在 `list_` 系列的 `member` ==都限定在 `list_head member`== 。**
:::info
如果 `list_` 系列的 `member` ,故意輸入 `struct` 中,不是 `list_head member` 的成員,應該會發生錯誤?該如何防呆?
:::
# 紀錄閱讀〈[因為自動飲料機而延畢的那一年](http://opass.logdown.com/posts/1273243-the-story-of-auto-beverage-machine-1)〉的啟發