--- 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)〉的啟發