# 2024q1 Homework5 (assessment) contributed by < [allenliao666](https://github.com/allenliao666) > ## 課程教材和 CS:APP 心得及提問 ### Chapter 1 看完第一章後,更了解 C 語言檔案的編譯流程,再透過 vscode 查看副檔名 .o 的檔案已非純文字內容,正是因為已被編譯為二進制的 object program 的緣故。 提問:不了解內文中有關<s>抽象化</s> 的意思 ``` As this figure suggests, files are abstractions for I/O devices, virtual memory is an abstraction for both the main memory and disk I/O devices, and processes are abstractions for the processor, main memory, and I/O devices. ``` > 參閱[資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary)並翻閱英英辭典,理解 abstract 的寓意,再回頭看 CS:APP。 :notes: jserv >應修改為抽象,查閱[牛津字典](https://www.oxfordlearnersdictionaries.com/definition/english/abstract_1?q=abstract)後得到以下解釋: based on general ideas and not on any particular real person, thing or situation abstract knowledge/principles. >詞源: from Latin abstractus, literally ‘drawn away’, past participle of abstrahere, from ab- ‘from’ + trahere ‘draw off’. >故應可把 abstraction 理解為從實例中抽離,只取其概念。以文中的檔案為例,我們無需深究不同硬體架構的 I/O 設備如何實做,僅需要知道檔案具有 I/O 設備的特質即可。 ### Chapter 2 複習 LP64 (包括 Linux, MacOS, Unix等)、 LLP64 (windows(x86-64, IA-64, and ARM64)) 等不同硬體架構對資料型別大小的定義。 使用 && 和 || 運算子時,只要第一個引數為真就會回傳結果,例如 a&&5/a 永遠不會發生 division by zero 中斷。 複習 [bitwise 操作篇](https://hackmd.io/@sysprog/c-bitwise)中的兩種未定義行為: * 左移超過變數長度,其結果未定義 * 右移一個負數時,可能是邏輯位移或是算術位移, C 語言標準未定義,由編譯器決定如何實作。gcc 的實作上是使用 arithmetic shift 。 有號數和無號數進行運算前,會將有號數隱性轉型為無號數後再運算。 有號數同時進行轉型為無號數和符號擴充時,會先執行符號擴充後,再轉型為無號數。例如: ```c short sx = -12345; /*-12345 */ unsigned uy = sx; ``` 效果等同 (unsigned) (int) sx 。 整數除法一律進位到整數,若 x < 0, y > 0 則 x / y = $\lceil$$\frac{x}{y}$$\rceil$ , 其餘結果皆為 x / y = $\lfloor$$\frac{x}{y}$$\rfloor$ 。若為有號數除法時,需使用算術右移。 複習[浮點數運算篇](https://hackmd.io/@sysprog/c-floating-point),浮點數的優點:可表示極大與極小值,相較整數能大幅避免 overflow 與 underflow ;浮點數的缺點:有效位數的減少。 因 IEEE754 的設計包含許多 quiet NaN ,因此必須注意運算的執行結果是否產生 NaN 。 提問: 1. 不了解下列 f2 經過轉型成整數後,為什麼反而輸出 NaN ? 2. 從 `printf` 的內容得知, f2經過轉型後仍為 float ,不知道原因為何? 若依照浮點數篇中提到的內容,0x7F800001在被宣告為 float 時,才會代表 NaN ,若被宣告為 int 時,應為2139095041。且若新增` int a = *(int *) &f2;` 輸出結果為7F800001。 ```c int main() { float f1 = (float) 0x7F800001; float f2; *(int *) &f2 = 0x7F800001; int a = *(int *) &f2; printf("f1:%f\n", f1); printf("f2:%f\n", f2); printf("a:%x\n", a); } ``` 輸出結果 ```c f1:2139095040.000000 f2:nan a:7f800001 ``` 發現只要輸入值大於 `0x7F800001` ,轉型成 float 後都會輸出`2139095040.000000`(即`0x7F800001`的十進位表示)。 >參考[浮點數運算和定點數操作](https://hackmd.io/@NwaynhhKTK6joWHmoUxc7Q/H1SVhbETQ?type=view),把 int 轉型成 float 時,不會每一個位元都一樣(如上述的 f1 ) [第三周測驗二](https://hackmd.io/@sysprog/linux2024-quiz3)中提到右移後,會有部分位元被捨棄,因此要用 d0, d1, d2 補回位元。為什麼不是加回 d2 就好,連 d0 和 d1 都要加回? ```c d0 = q & 0b1; d1 = q & 0b11; d2 = q & 0b111; ((((tmp >> 3) + (tmp >> 1) + tmp) << 3) + d0 + d1 + d2) ``` ## 閱讀〈因為自動飲料機而延畢的那一年〉的啟發 本文為作者想要完成製作自動飲料機的創業目標而努力的勵志故事,包括設定目標、實做自動飲料機、家人的不諒解和因為兵役問題被迫放棄創業等等過程。我最敬佩的是他們願意花費超過一年的時間全心全意投入在熱愛的事情上,可想而知,其中一定充滿焦慮、懷疑、迷茫,但他們仍願意全力向前,直到不可抗力的兵役中止他們的計畫。雖然從結果來說,他們的創業計畫100%失敗,但如同作者所說,正是因為過去不斷積累的各種經驗知識,才能支撐他們走到這一步,而且這段充滿挑戰的旅程也成為生命中無比珍貴的回憶。過去所投入的時間心力並非毫無價值,而是會在未來的某天發揮作用。 如同老師在課堂上說過 Linux 更新的頻率比打疫苗還快,正因為 Linux 存在的目的就是解決問題,隨著時代改變,當下面對的問題都不一樣,因此 Linux 必須針對問題提出對應的修改。這也是為什麼老師說不要直接去看 Linux kernel 程式碼的原因,在不清楚背景及框架的狀態下,我們如同瞎子摸象般,容易迷失在茫茫程式海中,更會未了自圓其說而落入舉燭的下場。 在撰寫開發紀錄的時候,在不經意間常常會舉燭,在未經實踐證明的情況下,理所當然的下註解。在觀摩許多同學的開發紀錄後,才知道如何用實驗和數據證明自己所言的正確性。此外在閱讀課程資料的時候,常常會發現自己對內容提到的名詞既熟悉又陌生,雖然似曾相似但也無法講出些道理,才發現自己其實從來都沒學會過,過去僅僅把定義背起來就覺得自己已經懂了,沒想到卻如此的不堪一擊,因此我努力在細節上更花心力。 --- quiet NaN vs, signaling NaN float-point exeception (FPE) TODO: 研讀 https://hackmd.io/@sysprog/r1wrjOp6a 並紀錄問題 (特別是數學!) TODO: 研究 Linux 核心關於錯誤修正的案例 (ECC),並且撰寫獨立的 Linux kernel module (LKM, for Linux v6.8) (比照第六次作業) > Ubuntu Linux 24.04 搭配 Linux v6.8