# 為什麼要深入學習 C 語言?
###### tags: `sysprog2018`
Contributed by <[`aben20807`](https://github.com/aben20807)>
:::success
「徹底瞭解自己」
:::
若不知底層運作、背後原理,那就只能當個使用者而非開發者
## 開發工具和規格標準
+ C、C++ 已經是不同的語言,部份功能 C++ 不能相容 C e.g. C99 designated initializers ~[27:46]~
+ C 語言是 WYSIWYG ~[18:18]~:高階的組合語言,可以較輕易的對應組合語言、二進位
### Object
+ 佔有空間的表示法
+ 延伸:struct 可利用長度為零的陣列來達到動態調整大小,C99 有 flexible array member [[source - 6.17 Arrays of Length Zero]](https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html)
+ 實驗:
```c
#include <stdio.h>
typedef struct {int x; int arr[];} Foo; // flexible array member 不可單獨存在
typedef struct {int x; int arr[0];} Bar;
int main(){
printf("sizeof(Foo):\t%ld\n", sizeof(Foo));
static Foo f = {1, {2, 3}}; // 必須 static
printf("sizeof(f):\t%ld\n", sizeof(f));
printf("f.x:\t\t%d\n", f.x);
printf("f.arr[0]:\t%d\n", f.arr[0]);
printf("f.arr[1]:\t%d\n", f.arr[1]);
printf("-------------------\n");
printf("sizeof(Bar):\t%ld\n", sizeof(Bar));
Bar b = {7, {8, 9}}; // warning: excess elements in array initializer
printf("sizeof(b):\t%ld\n", sizeof(b));
printf("b.x:\t\t%d\n", b.x);
printf("b.arr[0]:\t%d\n", b.arr[0]);
printf("b.arr[1]:\t%d\n", b.arr[1]);
return 0;
}
```
結果如下
+ 發現 flexible array members 能真的存到變動長度的值,但是 size 竟然不變
+ 不變的原因是因為 incomplete type 所以 sizeof 無作用
+ b 的 size 也不變,是因為 arr[0] 的 size 就是 0
```
sizeof(Foo): 4
sizeof(f): 4
f.x: 1
f.arr[0]: 2
f.arr[1]: 3
-------------------
sizeof(Bar): 4
sizeof(b): 4
b.x: 7
b.arr[0]: 1707756032
b.arr[1]: -809474503
```
+ zero-length arrays 可編譯且無警告的用法如下:
```c
Bar *ptrb = (Bar *)malloc(sizeof(Bar) + 2 * sizeof(int));
ptrb->arr[0] = 8;
ptrb->arr[1] = 9;
printf("ptrb->arr[0]:\t%d\n", ptrb->arr[0]); // 8
printf("ptrb->arr[1]:\t%d\n", ptrb->arr[1]); // 9
```
+ 既然上面方法可以,那測試不配置空間就直接用 `.` 來賦值給成員
+ 可以印出結果,但是發生 <span style="color: red;">*** stack smashing detected ***: <unknown> terminated</span>
+ 這是 gcc 的保護機制:存取到非法的 stack 空間,因此此種寫法相當危險
```c
Bar ano_b = {77};
ano_b.arr[0] = 88; // 非法存取!
ano_b.arr[1] = 99; // 非法存取!
printf("ano_b.arr[0]:\t%d\n", ano_b.arr[0]); // 88 // 非法存取!
printf("ano_b.arr[1]:\t%d\n", ano_b.arr[1]); // 99 // 非法存取!
```
+ 延伸其他討論
+ flexible array members 不一定要 static 賦值,也可以像 zero-length arrays 利用 malloc 動態配置
+ zero-length arrays 用 static 賦值 (有沒有用 static 都會警告) 時 arr 的兩個元素會初始化為 0 (不加 static 會是亂數)
+ 小整理
||flexible array members|zero-length arrays|
|:-:|:-:|:-:|
|syntax|arr[]|arr[0]|
|standard|ISO C99|ISO C90 (GNU C extension)|
|使用位置限制|限於 struct 的最後一個成員且不能唯一|無|
|空間分配|static initialization or malloc()|malloc()|
|e.g.|[struct f_midi](https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/drivers/usb/gadget/function/f_midi.c#L102)|[struct ip6t_entry](https://github.com/torvalds/linux/blob/6f0d349d922ba44e4348a17a78ea51b7135965b1/include/uapi/linux/netfilter_ipv6/ip6_tables.h#L128)|
### 語法糖 (Syntactic sugar)
+ `a[i]` 等價於 `*(a + i)` (限於 expression,不可用於宣告,但函式的 parameter 宣告又可等價)
+ `a->x` 等價於 `(*a).x`
### lvalue §6.3.2.1
+ locator value
+ 較好懂的解讀
+ 具有空間可以存放數值,上面提到 object 是佔有空間的表示
+ 通常會用 identifier 來代表儲存位置,可透過 dereference 得到真正的記憶體位址
+ 可以出現在 `=` 的左右邊
+ 又細分有 modifiable lvalue
+ 非 array type 、非 incomplete type 、無 `const` 修飾
### rvalue
+ 存放在記憶體中的資料,不可賦值,所以只能出現在 `=` 右方
+ 另外 `&` 運算子的操作也不行,因為其需要 lvalue 的運算元
:::info
### lvalue v.s. rvalue
修過 compiler 可能會比較知道,一個 language 可能有很多種 type
而 token 一開始在分析時就可以知道是整數、浮點數、字串、變數...
其中變數 (identifier) 會再有一個空間去存放 value 並記錄在 symbol table 中
這就導致了變數可以賦值,但是其他型別不行,也就是這裡的 lvalue
變數與其他型別經過四則混合運算後會變成一個數值,"通常"就不是一個變數,而是其他型別,也就是 rvalue
+ e.g.
```c
int x;
x = 8; // 型別為 int 的 object x 佔有空間並存放常數 8
int y = x; // x 可以出現在 `=` 右邊
3 = 8; // err: 3 是常數,非 lvalue
(x + 1) = 8; // err: (x + 1) 已經不是 lvalue
const int z = 7; // 是 lvalue 但不可改寫 (not a modifiable lvalue)
z = 9; // err: assignment of read-only variable 'z'
```
p.s. 實際 C 語言會比較複雜
+ 例如 dereference 可以用在 rvalue 上並獲得 lvalue e.g. `*(ptr + 1)`
:::
### pointer 運算 §6.5.3.2 ~[1:21:00]~
+ \+ 、\- 、\~
+ 並不是位址加 1,而是會依照 pointer 本身指向的 type
+ 實驗:(\~)☢️
scanf %s 可加可不加 &☢️
### WCHAR ~[1:25:18]~
+ 長度非固定
+ 有特別的 w 系列函式
+ 實驗:(中文字)☢️
### sizeof
+ `sizeof(struct A)` `sizeof(a)`
### incomplete type §6.2.5.22 ~[1:40:00]~
### NaN ~[2:01:00]~
+ 除以 0
+ INF
### const 位置 ~[2:11:00]~☢️
### GDB ~[2:19:00]~
+ 不同硬體架構、不同程式語言
+ 模擬器:模擬指令的執行
+ dwarf
+ -g v.s. -g3☢️
+ 前置處理器應用篇 (2016-06-29) ~[1:26:30]~