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