# 2018q3 Homework1
contributed by < [yichung279](https://github.com/yichung279) >
###### tags: `sysprog2018`
## 主題
* bitwise operation
* 你所知道的 C 語言 (C基礎複習)
* 你所不知道的 C 語言:開發工具與規格標準
* 你所不知道的 C 語言:指標篇
* 你所不知道的 C 語言:函式呼叫篇
## bitwise operation(及測驗第一題延伸)
* 簡介 : 逐個bit 作邏輯運算
* 應用 :
bit & 0 : = 0
bit | 1 : = 1
bit ^ 1 : toggle
跟相反的布林作運算時,bit皆不會改變
配合0xff、0x80、shift、~ 可取特定位置的bit(s)或快速改bit
* && / ||:
邏輯運算,數值只有0與~0
* 測驗延伸:
1.可配合卡諾圖,將真值表轉換為任何等價邏輯,並不只有xor可以轉換。
2.[nand/nor可以組合出所有邏輯運算子](https://market.cloud.edu.tw/content/vocation/control/tp_nh/logic/ch6/p3.htm)
## 你所知道的c語言(c基礎複習)
ref: https://openhome.cc/Gossip/CGossip/
### Ubuntu 16.04.5 LTS / GCC 5.5編譯器(我的環境)下的data type
* 整數
short: 2 bytes
int : 4 bytes
long : 8 bytes
* 浮點數
float : 4 bytes
double : 8 bytes
long double : 16 bytes
* 字元
char : 1 byte
> 這些規範不在規格書中,再 ieee754 及其他標準,這也保持了架構的靈活性。
### 指標
* & : 取址
* * : 傳值
* 指標運算: 前進一個**資料型態的記憶體長度**
* <s>雙重指標</s>: 就是**指標的指標**
:::danger
沒有「雙重指標」這說法,請依據 C 語言規格書,只有 the pointer to the pointer
:notes: jserv
:::
```clike
#include <stdio.h>
int main(void) {
int var = 10;
int *ptr = &var ;
// ptr為var的指標,型態為int,占4bytes
// var位址0x7ffedd04e2d2
// ptr == 0x7ffedd04e2d2
ptr + 1;
// 0x7ffedd04e2d6
ptr + 2;
// 0x7ffedd042da
int **pptr = &ptr;
// pptr為ptr的指標,型態為int,占4bytes
*pptr;
// *ptr == ptr == 10的指標 == 0x7ffedd04e2d2
**pptr;
// **pptr == 10
return 0;
}
```
:::info
善用 GDB,你可以直接傾印特定記憶體區間的內容,並用 macro 來客製化輸出
:notes: jserv
:::
## 你不所知道的 c 語言:開發工具和規格標準
### C 語言發展:
C是為了寫 Unix 而生的語言,而且可以自己編譯自己,先從從C 語言的子集合 C0 開始, C0 產生 C1 ,以此類推,一步步擴充規範。 C0 編譯器以組合語言開發。 見: [bootstraping](https://en.wikipedia.org/wiki/Bootstrapping_(compilers))
C0 有的關鍵字:
```
break goto
void int double
```
### ISO/IEC 9899:
直播中看到的疑問:
* Q: what is lvalue/rvalue?
* A: 這兩個名詞來自 `=` 兩邊的值,規格書中6.3.2.1:
>The name ‘‘lvalue’’ comes originally from the assignment expression E1 = E2,.....
---
* Q:為什麼會印出s的位址不是Hellow world 的ascii?
```clike
char str[] = 'Hellow world'//string literal
printf(%x, str)
```
* A: 根據規格書6.5.2.1 Array subscripting,`[]` 是pointer to object *type* 的 postfix,如 pointer to *int*,而str其實是 an array object ( a **pointer** to the initial element of an array object )
:::info
我不太理解這裡的 E1 到底是什麼,翻來翻去結果是 pointer to element (所以可以做指標運算)又是 array type (所以 E1 是lvalue 時,不能做modifiable value),導致 E1++ 不合法,但 E1+1合法。
所以 E1 是 pointer ,但是 array type 讓他行為不同嗎?而其他的pointer 會有 type嗎?(但[pjchiou的共筆](https://hackmd.io/J1wAu8KhTh20YzkalBmnUA?view)指 E1 不是指標,所以不能 E1++,有點困惑)
:::
:::success
array subscripting 限制了可用的 operator,請回頭看規格書 6.5.2 並且對照 gcc 編譯錯誤訊息
>6.5.2 第三點指出:`[]` 會把 E1 轉換成不能做lvalue的pointer[name=Yichung]
提及他人共筆時,應該述及 ID 或其他識別資訊。
:notes: jserv
:::
---
* Q:我不會解析這段:
>E1[E2] is identical to(*((E1)+(E2)))
* A:由於 E1 是 pointer ,所以這裡是的指標運算。
&E1[12] = E1 + 12,指向一塊未初始化的記憶體。
---
* Q:以前計概的array在教/學什麼?
* A:不知道
### gcc 及gdb:
compiler and debugger。
* gcc:
gcc -o [執行檔名稱] [要編譯的檔案]
* gdb:
[ypChien的共筆](https://hackmd.io/c/SJGEwHytX/https%3A%2F%2Fhackmd.io%2Fs%2FBJKQ0hhu7) 有精美的指令整理。
## 你不所知道的c語言:指標篇
* 頭腦體操:
查閱[運算子優先順序](https://zh.wikipedia.org/wiki/C%E5%92%8CC%2B%2B%E9%81%8B%E7%AE%97%E5%AD%90) 後,可以輕鬆作答。
* function pointer:
```clike
int foo();
int main() {
int (*funcptr)() = foo;
}
```
### `void *` 之謎:
指標操作有相關的風險,例如:用 "指向比較小 object 的 pointer" 指向 比較大的 object ,而導致不如預期的行為。
因為透過 `void*` 無法直接被存取的特性,我們便能保護 object。
危險:

直接不給過:

另有優點:
[stack overflow 的討論](https://stackoverflow.com/questions/11626786/what-does-void-mean-and-how-to-use-it)中,提及'`void` is nothing, `void*` is everything',作為function parameter時,很有靈活性。
:::danger
文字訊息不要用圖片來展現,一來很難搜尋 (和複製貼上),二來視覺障礙的朋友無法觀看,自然無法跟你交流討論
:notes: jserv
:::
### pointer to pointer:
透過 address ,我們可以輕易地在 A function 修改 B function 的 object ,而如果這個object是pointer時,就需要pointer to pointer 了。
### Type :
* Type 決定了object或函式回傳值的expression
* object types : describe objects
* function types : describe functions
* incomplete types : 描述物件但未決定物件(在記憶體中的)大小
* A pointer type 可以指向以下,並被稱為 referenced type
* a function type,
* an object type,
* an incomplete type
* 三位一體: Array, function, pointer types
都稱為 derived declarator types,都是從‘導’出來的型態
### row major cache
待研讀:
>Uno: 跟 cache line 有關 , column major 較容易會洗掉原本的 cache 內容
ref:[cenalulu的文章](http://cenalulu.github.io/linux/all-about-cpu-cache/)
### array vs pointer
syntax sugar
```clike
int *p, value; // 這樣宣告才不會搞混value的型態
int* p, value; // value實際上是int
```
物件占了一定的空間,型態決定這些空間怎麼表示。
strcpy/strcat:使用到不該使用的記憶體,就會發生問題了。
cat:concatenate。
malloc:會失敗,失敗跟配置0都會回傳null
>C語言把大家當成成熟的大人------宅色夫
argv有點可怕
:::warning
:question:
延伸:python有argv嗎?有,sys.argv 為什麼還要有argparse?因為有人的程式很複雜 argv不夠用
但經實驗sys.argv 跟argparse的速度差了三個數量級
:::info
附上實驗方法和數據,理工人說話要精準
:notes: jserv
>在我的筆電上,輸入一個環境參數,argv大約使用了0.000006s,argparser 約需要0.004s,一直想用程式做更大規模的實驗,有機會會補上完整數據。[name=yichung279]
:::
```clike
void Foo(int i, float f);
void Bar()
{
int num = 1;
Foo(num, 2.0);
}
```
num 與 2.0 即為 引數 (Argument),或稱為 函式引數 (Argument of a Function)。
i 與 f 則為 參數 (Parameter)。
function designator ,因為不是搭配 &, sizeof 使用,所以會被轉成為 pointer to function
就算 ***fptr,再多的 * 都鞥function designator。
```clike
#include <stdio.h>
```
~~int *func1()~~
```clike
char *func1()
{
char *p = "hello world";
return p;
}
```
~~int *func2()~~
```clike
char *func2()
{
char p[] = "hello world";
return p;
}
int main()
{
printf("%s\r\n", func1());
printf("%s\r\n", func2());
}
```
`""` 會使用 static area 中的記憶體,進行 string literal,[] 會把上述的結果複製至stack中。
而func2() 指向的 array 在 func2 生命週期結束時,一起被釋放了,所以 func2() return值 便指向了 null。
但fun1() 指向 static area 裡的空間,func1生命週期結束後依然存在,所以 func1() return值 依然指向字串。
::: info
詭異的事:一開始程式打錯 char 打成 int ,func1() 仍印出 "hello world"。
於是試圖做以下實驗:
```clike=
int func()
{
long a = 0x12345678;
return a;
}
int main(){}
```
gdb :
whatis func():type = int
x func(): 0x12345678
p func(): 305419896
難以理解一個 int type ,有 unsigned long 的行為。一個 object 不是以 type 決定 expression 嗎?
function call 不能以 object 觀點檢視?(待我看完函式篇
>後來做到 big-endian / little-endian 的題目就懂了。-[name=yichung279]
:::
::: info
OSX把 `/n` 拿掉會多印一位,GNU/linux不會多印,online compiler不會多印,為何有不同的行為,為何不是印到OS介入為止。(UB?)
:::
```clike=
int main()
{
char s[] = "hello world";
s[11] = 'a';
puts(s);
}
```
## 你所不知道的C語言:函式呼叫篇
### C 語言歷史:
* 早期 C 語言 (1972-1973) -> K&R C (1976-1979) -> ANSI C (1983-1989) -> ISO
* 「不允許 nested function」這件事簡化了 C 編譯器的設計
### Something behind "Hello world"
main printf 本身就是 function,涉及func call
呼叫標準函式庫,涉及linking
before main
memory layout