分享到plurk 分享到twitter 分享到facebook

版本 5360c7099f67c790a0315129481d9e1ae992c7f7

User/D4nnyLee

D4nnyLee(李韋杰)

  • 成功大學資訊系 111 級

Linux Kernel Internals 2021 春季班

問題選答

a) 知道 x - y < 0 敘述為何不能寫為 x < y 嗎? (CS:APP 第 2 章)

因為這兩個敘述並不會在所有情況下都得到相同的結果。

假設 x, y 的型別都為 int8_t ,則 x, y 能表達的最小值就是 -128 ,因此很容易就能舉出 x = -128, y = 1 這個反例。

  • x - y 得到的結果為 127,這是 signed integer underflow 所造成的結果,所以 x - y < 0 會得到 false 。
  • x < y 就只是單純比較 x 和 y 的大小,而顯而易見的 -128 < 1 ,因此 x < y 會得到 true 。

由這個反例可以知道 x - y < 0 和 x < y 可能會得到不同的結果,因此不可以將兩個敘述劃上等號。

d) 知道 Linux 核心 < include/linux/list.h> 裡頭 #define list_for_each_prev(pos, head) for (pos = (head)->prev; pos != (head); pos = pos->prev) 這樣的巨集到底在做什麼?以及 head 使用時需要加小括號,為何?

巨集功能

list_for_each_prev(pos, head) 的作用為反向迭代 head 這個 linked list 上的元素。

pos 為用於迭代的指標,pos 和 head 的型別預期都是 struct list_head * 。

為何需要小括號

為了避免因為 operator 優先順序的關係而造成非預期的行為。

在巨集裡面可以看到 pos != (head) 這段敘述,這邊就用 != 這個 operator 來舉例。

定義一個巨集 different(x, y) ,預期在 x 和 y 不相等的時候會回傳 true ,否則就回傳 false 。

#define different(x, y) (x != y)

如果只寫這樣的話如果呼叫 different() 時是寫 differernt(x, y = 3) ,巨集展開後就會變成 (x != y = 3)。

因為 != 會比 = 先執行,所以執行到 = 的時候左邊是 != 的結果,而這個結果並不是一個 lvalue。 最後就會因為對非 lvalue 賦值而造成編譯錯誤。

要修正這個錯誤就要將定義改成

#define different(x, y) ((x) != (y))

這樣展開之後就會變成 ((x) != (y = 3)),因為括號內的敘述會先被執行,所以 = 會先被執行,然後才是 != ,因此得到的結果就是預期的 != 的回傳值。

心得

這堂課的內容許多都是之前沒有接觸過的領域,因此時常都要翻閱一堆文件並且閱讀英文內容,這件事情讓我深深體會到我閱讀能力的不足。因為讀得很慢所以必須要花更多時間再看同一份文件上,要查的文件一旦多起來的話就更是看都看不完,所以以後除了寫 code 以外還要時常練習英文閱讀。

這堂課中我最有興趣的部份是跟 bit-wise 操作有關的部份,不管是作業還是上課測驗題中都時常出現利用 bit-wise 操作來取代原本代價高昂的操作(例如除法、取餘數等),藉此來提高程式效能,我覺得這部份就跟腦筋急轉彎很像,並且很考驗對二進位的理解程度,我很享受思考如何利用二進位來簡化原本操作的這個過程,並且因為做了這個優化之後程式實際上效能有變好的話也讓人很有成就感。

最後課堂主要集中在平行程式設計的教學上,這部份就是幾乎沒有接觸過的內容,因此學習的速度非常緩慢,但是教授也很貼心的提供了許多的學習教材,只要花時間就可以慢慢把這些都內化成自己的東西,非常謝謝教授提供了這麼多的資源!

自我評分

41/50