--- title: C語言技巧篇 心得 tags: C 語言筆記 --- ## C語言技巧篇 心得 ### 從矩陣操作談起 * [compound literal](https://en.cppreference.com/w/c/language/compound_literal) * [宣告的 lifetime 與迴圈關係](https://stackoverflow.com/questions/69070100/compound-literal-is-created-once-for-a-given-scope),簡單來說就是只存在於那一圈迴圈中 ```c= while () { q = p; // p is invalid in the second iteration p = &((struct s){ j++ }); } ``` * [designated initializers](https://gcc.gnu.org/onlinedocs/gcc/Designated-Inits.html) * 範例1 ```c= typedef struct s { char *name; int height; } S; S my_S = { .name = "John", .height = 18 }; ``` * 範例2 ```c= const char *lookup[] = { [0] = "Zero", [1] = "One", [4] = "Four" }; assert(!strcasecmp(lookup[0], "ZERO")); ``` 也可用 enum ```c= enum cities { Taipei, Tainan, Taichung, }; int zipcode[] = { [Taipei] = 100, [Tainan] = 700, [Taichung] = 400, }; ``` * 更好的封裝程式碼(以矩陣為例) * [matrix_oo](https://github.com/jserv/matrix_oo) ### 追蹤物件配置的記憶體 * 當我們使用 struct 定義的時候,定義的結構通常都會非常的複雜。所以當我們要釋放這些記憶體空間的時候,會非常麻煩且容易出錯。這時可以用老師的自動管理機制 nalloc 以及 nfree * [nalloc 實作](https://github.com/jserv/nalloc) * strdup vs strdupa * strdup: 會呼叫 malloc 來配置足夠長度的記憶體,資料放在 heap,需要適時呼叫 free 以釋放資源 * strdupa: 透過 alloca 函式來配置記憶體,資料存在 stack,而非 heap。當函式返回時,整個 stack 空間就會自動釋放,不需要呼叫 free * Implementing smart pointers for C * __ attribute __ : GCC extension 的一個編譯屬性,用於讓編譯器在編譯時做特殊的標記處理、錯誤處理或優化 * 可以設定的屬性有 Function Attribute 、Variable Attribute 和 Type Attribute * 利用 GCC extension: attribute cleanup 來實作 ```c= /*Variable Attribute*/ #define autofree \ __attribute__((cleanup(free_stack))) /*Function Attribute*/ __attribute__ ((always_inline)) inline void free_stack(void *ptr) { free(*(void **) ptr); } ``` * [free_stack(void *ptr) 解釋](https://stackoverflow.com/questions/60718165/why-gnu-extension-cleanup-work-with-no-parameter) * 使用 ```c= int main(void) { autofree int *i = malloc(sizeof (int)); *i = 1; return *i; } ``` ### Transparent union * 用 GCC transparent union 實作 繼承和多型 * [範例](http://toves.freeshell.org/xueg/) ```c= # include <stdio.h> enum argtype { T_STRING, T_POINT, }; typedef enum argtype ARGTYPE; struct point { ARGTYPE type; float x; float y; }; typedef struct point POINT; struct string { ARGTYPE type; char* s; }; typedef struct string STRING; union example { POINT* pt; STRING* str; }; typedef union example EXAMPLE __attribute__ ((__transparent_union__)); void transparent_union_example(EXAMPLE arg) { ARGTYPE type = arg.str->type; /* arg.pt->type would also do */ switch(type) { case T_STRING: { char* s = arg.str->s; printf("string='%s'\n", s); } break; case T_POINT: { POINT* pt = arg.pt; printf("p(x,y)=(%f,%f)\n", pt->x, pt->y); } break; } } main() { POINT pt = { T_POINT, 0.5, 7.5 }; STRING str = { T_STRING, "Test" }; transparent_union_example (&str); /* no casts required */ transparent_union_example (&pt); } ``` ### 巨集 & typeof * 以下程式碼會輸出三次 doOneTime,不符合預期的兩次 ```c= #define max(a, b) (a > b ? a : b) void doOneTime() { printf("called doOneTime!\n"); } int f1() { doOneTime(); return 0; } int f2() { doOneTime(); return 1; } int main() { int result = max(f1(), f2()); } ``` * 使用 typeof 修改巨集 ```c= #define max(a, b) ({typeof(a) _a = a;typeof(b) _b = b;_a > _b ? _a : _b;}) //#define max(a, b) a > b ? a : b void doOneTime() { printf("called doOneTime!\n"); } int f1() { doOneTime(); return 0; } int f2() { doOneTime(); return 1; } int main() { int result = max(f1(), f2()); } ```