# 2018q3 Homework1 contributed by < `jason53415` > :::danger 你的提問呢?回顧你過去開發的程式,難道沒想到概念上有衝突或者激發出更多想法嗎? :notes: jserv ::: ## 開發工具與規格標準 ### 重點 * C++ * 過於複雜,且 C++ 14 到 C++ 17 一口氣加入了許多內容,讓開發者難以掌握。 * 雖然在許多情況下與 C 語言相容,但從 C99 開始兩者的差異已經大到可以視為兩種不同的語言。 * 開源授權規範 * GPL:一種 Copyleft 授權條款,如果在開發中使用了其他 GPL 協議的軟體,則這個軟體也必須以 GPL 發布,需要開源且禁止商業發布。 * LGPL:如果僅是調用、連接 LGPL 的軟體,就可以不需開源並可做商業利用。 * MIT:相對寬鬆的軟體授權條款,只要在發行時包含原許可協議的聲明,基本上沒有其他的限制。 * 語言規格書 * 第一手資料,許多問題以及定義在語言規格書中就可以找到答案。 * 在正式發布之前會釋出許多草案,即便在定下規格標準數年之後,仍然會因為商標、語意容易混淆等問題而不斷微調。 * GDB * GDB 可以支援許多不同的硬體架構與程式語言,並且可以當作 instruction simulator。 * 使用 GDB 可以調整程式執行的順序,也可以避免使用過多 ```printf()``` 改變程式的行為。 ### 心得 在 [Understand more about C](https://www.slideshare.net/YiHsiuHsu/understand-more-about-c) 中有提到一個很有趣的問題是關於 ```a = a++;``` 的執行結果。例如有以下的 C 語言程式,那最後的輸出到底是 0 或者是 1 呢? ```C= #include <stdio.h> int main() { int a = 0; a = a++; printf("%d\n", a); } ``` 實際編譯與執行結果: ```shell= $ gcc -std=c99 -Wall -o test test.c test.c: In function ‘main’: test.c:5:7: warning: operation on ‘a’ may be undefined [-Wsequence-point] a = a++; ~~^~~~~ $ ./test 0 ``` 而翻閱 C99 規格書之後會找到以下的解釋: > Between the previous and next sequence point an object shall have its stored value modified at most once by the evaluation of an expression.^72)^ Furthermore, the prior value shall be read only to determine the value to be stored.^73)^ > 73) ) This paragraph renders undefined statement expressions such as > ```c > i = ++i + 1; > a[i++] = i; > ``` :::warning 所以實際上在 C99 的規範中,類似這樣的表示法是未定義的,不過我們仍然可以執行出實際的值。所以問題就出現了,到底編譯器最後是依據什麼去決定最後的值呢? :::info UB 給予編譯器實作的自由,包含最佳化的空間,參見 [你所不知道的C語言: 未定義行為篇](https://hackmd.io/s/Skr9vGiQm) :notes: jserv ::: ## 指標篇 ### 重點 * C 語言 * 專為開發 Unix 設計的程式語言,透過記憶體映射的方式,可以使用指標直接控制硬體底層。 * 可以用 C 語言本身編寫自己的編譯器,以及開發許多其他語言的編譯器。 * qsort * 不一定要用 quicksort 來實做,而且可以自由規定要排序的元素數量與大小。 * 利用 function pointer 所指到的自定義函式來決定排序。 * Object * 並非只有物件導向程式語言會討論到物件,從 C 語言的規格書就可以得知,物件是 C 語言中非常重要的概念。 * 物件有其生命週期 (lifetime) ,生命週期內會有對應的常數記憶體位址,才能使用指標進行操作。 * Alignment * 在許多硬體架構上, C 語言的一些變數會有對齊的要求,例如 4 bytes 大小的 int 變數可能就必須起始於一個可以被 4 整除的地址。 * 在依序宣告許多不同型態的變數時,為了符合地址對齊的要求,可能就必須加入許多填充 (padding) ,等同於是被浪費的空間。 * 指標的指標 * 不能講成「雙指標」,「指標的指標」是有從屬關係的指標。 * C 語言中函式的呼叫只有 call-by-value ,善用指標的指標,可以使函式的輸入不會被其生命週期限制。 * Forward declaration * 將宣告與詳細的定義與實做分裝在 .h 檔與 .c 檔,這樣即便開發者不知道真正實做細節,只要使用預先宣告的函式指標,就可以正確操作函式。 * 區分出介面與實做,可以加強軟體開發的分工,並兼顧在不同系統上的相容性。 ## 函式呼叫篇 ### 重點 * Nested function * C 語言中沒有 nested function ,所有 function 在語法層面都位於最頂層 (top-level) 。 * 要實現 nested function 需要 static link 的機制,這會讓編譯器設計起來較為複雜。 * MMIO (memory mapped I/O) * 可以使用操作記憶體的方式直接控制裝置 * PDP-11 是一個早期便使用 MMIO 的範例