# 2018q3 Homework1 contributed by < [osamchiu](https://github.com/osamchiu) > - [x] 開發工具和規格標準篇 - [x] 指標篇 - [x] 函式呼叫篇 - [x] 遞迴呼叫篇 - [x] 前置處理器應用篇 - [ ] goto 和流程控制 - [ ] linked list 和非連續記憶體操作 - [ ] 技巧篇 - [ ] GNU/Linux 開發工具 ## 開發工具和規格標準篇 > C is quirky, flawed, and an enormous success. Although accidents of history surely helped, it evidently satisfied a need for a system implementation language efficient enough to displace assembly language, yet sufficiently abstract and fluent to describe algorithms and interactions in a wide variety of environments. —— Dennis M. Ritchie 在以前寫C的時候根本沒有想那麼多,就當成了一個普通的語言再用,其實到頭來也變成雖然已經過了幾年,但是對C而言沒什麼深度的瞭解。 ### license ##### GPLv3 做動態連結時有較大的限制 ##### MIT License 別把作者名字塗掉就可以用(夠簡單) ==對於compiler而言,是不是可以認知為如果我不是抄襲他們的原始碼,只是單純利用他們的compiler我就等於可以免費使用? 即使我的程式是有收益的??== :::info 是的,在不違反當地法規 (如美國對加密演算法的出口管制) 的前提下,MIT License 允許你使用該授權的編譯器自由地編譯程式碼,後者也能自由地運用,包含商業行為 :notes: jserv ::: ==謝謝老師回答 請問GPLv3也是如此嗎?== :::info GPLv3 的狀況複雜一點,要看 GPLv3 授權的編譯器產生的程式碼是否附帶同樣 GPLv3 的程式碼,這部分要對照 [Exceptions to GNU Licenses](https://www.gnu.org/licenses/exceptions.html) 來解讀。 請花點時間讀 GPLv3 一類的授權條款,一輩子受用的 :notes: jserv ::: ==好的 謝謝老師 我再看看詳細內容 感謝你回答!== ### 有趣的地方 終端機其實是檔案 ### compiler的由來 編譯器開發 C的編譯器怎麼來? C0>C1>...>CN bootstrapping ## 指標篇 >A pointer type may be derived from a function type, an object type, or an incomplete type, called the referenced type. A pointer type describes an object whose value provides a reference to an entity of the referenced type. A pointer type derived from the referenced type T is sometimes called ‘‘pointer to T’’. The construction of a pointer type from a referenced type is called ‘‘pointer type derivation’’. >Array, function, and pointer types are collectively called derived declarator types. A declarator type derivation from a type T is the construction of a derived declarator type from T by the application of an array-type, a function-type, or a pointer-type derivation to T. 不管什麼在C裡面只有call by value ```C=1 int B = 2; void func(int *p) { p = &B; } int main() { int A = 1, C = 3; int *ptrA = &A; func(ptrA); printf("%d\n", *ptrA); return 0; } ``` ```graphviz digraph structs { node[shape=record] {rank=same; structa,structb,structc} structp [label="p|<p>&B"] structptr [label="<name_ptr> ptrA|<ptr> &A"]; structb [label="<B> B|2"]; structa [label="<A> A|1"]; structc [label="<C> C|3"]; structptr:ptr -> structa:A:nw structp:p -> structb:B:nw } ``` ```clike=1 int B = 2; void func(int **p) { *p = &B; } int main() { int A = 1, C = 3; int *ptrA = &A; func(&ptrA); printf("%d\n", *ptrA); return 0; } ``` ```graphviz digraph structs { node[shape=record] {rank=same; structa,structb,structc} structp [label="p(in func)|<p> &ptrA"] structadptr [label="&ptrA(temp)|<adptr> &ptrA"] structptr [label="<name_ptr> ptrA|<ptr> &B"]; structb [label="<B> B|2"]; structa [label="<A> A|1"]; structc [label="<C> C|3"]; structptr:ptr -> structb:B:nw structadptr:adptr -> structptr:name_ptr:nw structp:p -> structptr:name_ptr:nw } ``` 對C而言function就是只有複製傳copy的 所以傳pointer to pointer就是等於把原先的pointer的value(另一個address)複製一份傳入function 這樣才能真的改變到 ## 函式呼叫篇 ![](https://hackpad-attachments.s3.amazonaws.com/embedded2015.hackpad.com_2q5oxqltYTG_p.299401_1449482197657_undefined) 把整個函數的部分複習了一遍 ## 遞迴呼叫篇 #### 對於Recursive在compiler的效率 以老師提供之費氏數列程式碼 利用godbolt進行實驗 - comiplier version:X86-64 gcc 8.2 ``` C //test code int fib(int n) { if (n == 0) return 0; if (n == 1) return 1; return fib(n - 1) + fib (n - 2); } int fib1(int n, int a, int b) { if (n == 0) return a; return fib(n - 1 , b, a + b); } ``` - C++ ``` ASM fib(int, int, int): push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], edi mov DWORD PTR [rbp-8], esi mov DWORD PTR [rbp-12], edx cmp DWORD PTR [rbp-4], 0 jne .L2 mov eax, DWORD PTR [rbp-8] jmp .L3 .L2: mov edx, DWORD PTR [rbp-8] mov eax, DWORD PTR [rbp-12] add edx, eax mov eax, DWORD PTR [rbp-4] lea ecx, [rax-1] mov eax, DWORD PTR [rbp-12] mov esi, eax mov edi, ecx call fib(int, int, int) nop .L3: leave ret fib1(int, int, int): push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], edi mov DWORD PTR [rbp-8], esi mov DWORD PTR [rbp-12], edx cmp DWORD PTR [rbp-4], 0 jne .L5 mov eax, DWORD PTR [rbp-8] jmp .L6 .L5: mov edx, DWORD PTR [rbp-8] mov eax, DWORD PTR [rbp-12] add edx, eax mov eax, DWORD PTR [rbp-4] lea ecx, [rax-1] mov eax, DWORD PTR [rbp-12] mov esi, eax mov edi, ecx call fib(int, int, int) nop //==here== .L6: leave ret ``` - C ``` ASM fib: push rbp mov rbp, rsp push rbx sub rsp, 24 mov DWORD PTR [rbp-20], edi cmp DWORD PTR [rbp-20], 0 jne .L2 mov eax, 0 jmp .L3 .L2: cmp DWORD PTR [rbp-20], 1 jne .L4 mov eax, 1 jmp .L3 .L4: mov eax, DWORD PTR [rbp-20] sub eax, 1 mov edi, eax call fib mov ebx, eax mov eax, DWORD PTR [rbp-20] sub eax, 2 mov edi, eax call fib add eax, ebx .L3: add rsp, 24 pop rbx pop rbp ret fib1: push rbp mov rbp, rsp sub rsp, 16 mov DWORD PTR [rbp-4], edi mov DWORD PTR [rbp-8], esi mov DWORD PTR [rbp-12], edx cmp DWORD PTR [rbp-4], 0 jne .L6 mov eax, DWORD PTR [rbp-8] jmp .L7 .L6: mov edx, DWORD PTR [rbp-8] mov eax, DWORD PTR [rbp-12] add edx, eax mov eax, DWORD PTR [rbp-4] lea ecx, [rax-1] mov eax, DWORD PTR [rbp-12] mov esi, eax mov edi, ecx call fib1 //==here== .L7: leave ret ``` ==發現在C的版本裡面直接call fib1 而在C++版本中呼叫後會有一個nop(查資料後發現是延時等待) 仔細思考後來是想不太到為什麼會有這樣的差異== ps:同樣程式碼在x86-64 gcc 7.3卻沒有該nop指令 :::info 和 optimization order 有關,你可以新增編譯參數 `-march=native -mtune=native -Ofast` 再重新編譯 :notes: jserv ::: #### file loading的包裝型態 在FILE以及DIR的函式內部回傳利用FILE* 以及DIR*作為回傳 可以有效的包裝讀取以及實際存取的狀況 ## 前置處理器應用篇