# 2018q3 Homework1
contributed by <`AlecJY`>
## 開發工具和規格標準篇
### 為何不探討 C++
* C++ 是 meta language
* 改版很快
* 1999 年 C 和 C++ 分道揚鑣
#### 授權
* glibc -- LGPL
* LGPL -- **動態連結**的情況下不會受到License影響
* MIT License -- 不要把作者塗掉就好
### 第一個 C 編譯器
* 用 ~~property~~ proprietary compiler 編一個較簡單的 c compiler
:::danger
"property compiler" 是什麼?
:notes: jserv
:::
### C99
* 最終版規格書要錢,但是Draft不用
* `&` 在指標要念 address of
* `*` value of
* [] Array Subscripting Operator
* cdecl
### GDB
* 改 kernel 很難
* 要用 gdb 記得在 gcc 參數加 ```-c```
* rr 可以把crash錄下來
## 指標篇
* C 設計給 Unix
* 控制記憶體
* pointer type 不能乘除
* L(ocator)value
* return type defaults to "int"
* 某些硬體架構需要alignmnet
* *** 情境
* int \*ptr, value; /\* good \*/
int\* ptr value; /\* bad \*/
"value" type is int
* typeof 不是 ISO standard C 的一部份
:::info
`typeof` 這個 GNU extension 有什麼作用?能否在 GitHub 找到應用案例並解釋呢?
:notes: jserv
:::
:::info
`typedef`用來幫資料型別取別名
底下這段在 GitHub 找到的程式碼就是利用 `typedef` 處理不同環境下的型別問題 [[來源]](https://github.com/xsoameix/wz/blob/15e6962cf3203402864421fa4e821cd35d5b4fd2/src/type.h#L33)
``` C
#if defined(WZ_ARCH_32)
typedef signed int wz_intptr_t;
typedef unsigned int wz_uintptr_t;
#elif defined(WZ_MSVC)
typedef signed __int64 wz_intptr_t;
typedef unsigned __int64 wz_uintptr_t;
#else
typedef signed long wz_intptr_t;
typedef unsigned long wz_uintptr_t;
#endif
```
只是 `typedef` 應該是 C99 Standard 的一部份,在 6.7.7 節中有說明 `typedef` 詳細的用法,推測老師想要問的是 `typeof`
`typeof` 用來取得 type ,在語法上用起來像由 `typedef` 定義出來的 type name
在 GitHub 上找到這段程式碼 [[來源]](https://github.com/Stichting-MINIX-Research-Foundation/minix/blob/03ac74ede908465cc64c671bbd209e761dc765dc/usr.sbin/pwd_mkdb/pwd_mkdb.c#L193)
``` C
#define SWAP(sw) \
((sizeof(sw) == 2 ? (typeof(sw))bswap16((uint16_t)sw) : \
(sizeof(sw) == 4 ? (typeof(sw))bswap32((uint32_t)sw) : \
(sizeof(sw) == 8 ? (typeof(sw))bswap64((uint64_t)sw) : (abort(), 0)))))
```
這個 Macro 判斷 `sw` 的大小然後對 `sw` 做 byte order 轉換,轉換前先把 `sw` 轉型成 byte order 轉換函式所接受的型別,再將轉換後的值利用 `typeof` 轉型回 `sw` 原本的型別
參考資料
* [C99 Standard](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf)
* [Referring to a Type with `typeof`](https://gcc.gnu.org/onlinedocs/gcc/Typeof.html)
:::
## 函式呼叫篇
* parameters 和 local variables 都會佔 stack 空間
* `if (ptr) free(ptr);` => `free(ptr);`
* free完就把指標設定成null可以避免double free
## 遞迴呼叫篇
* 遞迴程式不見得會比迭代慢
* 用 clang/llvm 輸出 `-O2` (基本的最佳化) 有些遞迴和迭代轉譯出的組合語言會完全一樣
* 尾端遞迴(tail recursion)做得好,最佳化可以不增加新的系統堆疊,但是不是每個語言編譯器都有支援
* Tail recursion -- 把中間的結果當作參數傳遞,可以避免重複的運算
* 就像是迭代的區域變數放在參數傳遞
* 編譯器在最佳化的時候有可能會改變stack frame的行為
* IEEE 754 的浮點數沒有乘法和加法交換律
:::info
底下是用 JShell 測試 IEEE 754 加法的結果
```
jshell> 0.1 + 0.2 + 0.3
$1 ==> 0.6000000000000001
jshell> 0.3 + 0.2 + 0.1
$2 ==> 0.6
```
第一次聽到 IEEE 754 的乘法和加法沒有交換律覺得很不直覺,仔細想想他的儲存方式後也覺得還好了
:::
## 前置處理器應用篇
* C11 的 `_Generic`
## goto 和流程控制篇
* `do { ... } while(0)` 避免 dangling else
* case 是一個 label
* coroutine
## linked list 和非連續性記憶體操作
* ADT(Abstract Data Type) -- 對特定資料結構建立數學模型
### Circular linked list
* 龜兔賽跑演算法 -- 如果有循環,一個快一個慢的情況會相遇
## 技巧篇
* 傳入指標後直接修改值,比傳入一個 object 再回傳需要多一些檢查
:::info
「[停止使用 strncpy 函數!](http://blog.haipo.me/?p=1065)」的連結已經失效了,所以閱讀 [Wayback Machine 保存的版本](https://web.archive.org/web/20170717113942/http://blog.haipo.me/?p=1065)
* 如果 src 的長度小於 n , dest 剩下的位置會補 0
* src 的長度大於 n 的話, dest的結尾不會補 0
* strdup 會用 malloc 分配足夠的空間來放置複製的字串,只是使用完要記得 free
* strdupa 將複製的字串放在 stack ,所以離開函式後就會釋放空間
:::