linux2019
contributed by < ambersun1234
>
$ uname -a
Linux 4.15.0-45-generic #48~16.04.1-Ubuntu SMP Tue Jan 29 18:03:48 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
$ gcc -v
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.11)
qtest
得以支援Case | Insertion sort | Quick sort | Merge sort |
---|---|---|---|
Average case | \(O(n^2)\) | \(O(nlogn)\) | \(O(nlogn)\) |
Worst case | \(O(n^2)\) | \(O(n^2)\) | \(O(nlogn)\) |
make averagePlot
make worstPlot
segmentation fault
。後來在追蹤時發現到是在 quick sort 60000 的時候發生;結果是因為 stack size 不夠大所導致,使用 ulimit -s 65536
更改 stack size 即可解決macro 是在編譯階段進行展開的,根據 man gcc
裡面的提到
-E
Stop after the preprocessing stage;
do not run the compiler proper.
The output is in the form of preprocessed source code,
which is sent to the standard output.
在 compile 的時候加上 -E 這個參數即可以觀察到展開巨集之後的程式碼,就可以發現到說 macro 全部被展開到程式碼裡面( 我覺得是類似 find and replace )
function call 編譯完成後並不會像 macro 一樣全部展開到程式碼之中,而是在記憶體中實際佔有空間的。在演算中有學到 , 每次的 function call 都是要對 stack 進行 push pop 的,而這樣的操作是很耗時間的
綜合以上, macro 不會發生 function call 的 push pop 的操作,可以減少時間成本,但相對的,由於是展開巨集,所以會造成空間的浪費
那 linux 會採用 macro 實做 linked list 我想很大的原因是要避免 stack 的 push pop 造成多消耗時間
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
typeof
是 gnu c extension,它可以取得參數的型態,比如說
int a;
typeof(a) b;
int b;
,typeof 會返回參數的類型,a 為 int 型態,因此 typeof(a) 會變成 int#define container_of(ptr, type, member) \
__extension__({ \
const __typeof__(((type *) 0)->member) *__pmember = (ptr); \
(type *) ((char *) __pmember - offsetof(type, member)); \
})
#define offsetof(TYPE, MEMBER) ((size_t)&((TYPE *)0)->MEMBER)
#include <stdio.h>
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
typedef struct mdata {
int a, b, c;
char *hello;
struct mdata *next;
} data;
int main() {
printf("-- a = %d --\n", offsetof(data, a));
printf("-- b = %d --\n", offsetof(data, b));
printf("-- c = %d --\n", offsetof(data, c));
printf("-- hello = %d --\n", offsetof(data, hello));
printf("-- next = %d --\n", offsetof(data, next));
return 0;
}
-- a = 0 --
-- b = 4 --
-- c = 8 --
-- hello = 16 --
-- next = 24 --
#define container_of(ptr, type, member) \
__extension__({ \
const __typeof__(((type *) 0)->member) *__pmember = (ptr); \
(type *) ((char *) __pmember - offsetof(type, member)); \
})
GCC uses the extension attribute when using the -ansi flag to avoid warnings in headers with GCC extensions. This is mostly used in glibc with function declartions using long long
((type *)0)->member
的指標變數 __pmember
並將 ptr
指派給 __pmember
list.h
還定義一系列操作,為什麼呢?這些有什麼益處?LIST_POISONING
這樣的設計有何意義?LIST_POISONING
一系列定義於 linux/poison.h 中。該檔案定義了許多的 magic number ,這些 magic number 被用在許多的地方 e.g. mm, arch, drivers, kernel 等。我有找到一篇 what is the meaning of 0xdead000000000000? 是在探討這些 magic number 的設計考量點。LIST_POISONING
,可以很快速的辨別是哪裡出錯list_for_each_safe
和 list_for_each
的差異在哪?"safe" 在執行時期的影響為何?
#define list_for_each_safe(node, safe, head) \
for (node = (head)->next, safe = node->next; node != (head); \
node = safe, safe = node->next)
safe
,去紀錄當前 node 的下一個。直播中有提到,如果 head 不見了,那麼就會出錯,由於 linux kernel 的 linked list 是屬於 circular
,當 head 在執行的時候被刪除了,safe 這個變數可以先將 head 的下一個保存起來,確保執行順利@
符號,這有何意義?你能否應用在後續的程式開發呢?Doxygen
是一個可以將程式裡的特定註解轉換成 Document 的產生工具@
是告訴 Doxygen 說這一行要轉換成為 Document,比方說
tests/
目錄底下的 unit test 的作用為何?就軟體工程來說的精神為何?tests/
目錄的 unit test 可如何持續精進和改善呢?