---
# System prepended metadata

title: C語言技巧篇 心得
tags: [C 語言筆記]

---

---
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()); 
}
```