[心得] Compound literals, flexible array me …
下面是我以前學C99新功能的心得,跟大家分享。
假設有一個struct S有兩個欄位x和y,在ANSI C年代,如果要把x, y設定值
只能這樣寫
A.x = 1;
A.y = 1;
在C99則允許這樣
struct S A = (struct S) {1, 1};
方便很多,這功能稱為compound literals
如果要傳參數給function,也可以這樣寫f( (struct S){1, 1} );
甚至還可以對他取位址
struct S *p = &(struct S) {1, 1}; // 取位址
甚至連原始型態都可以取位址
int *p = &(int) {1}; // p = &1不合法..
可以想像compound literal是一個匿名的變數,但是他跟string literal又稍有不同
char *p = "Hello";
p[1] = 'a'; // 會出錯 因為string literal是const
然而
struct S *p = &(struct S) {1, 1};
*p = (struct S) {0, 0}; // 合法
不過當匿名的變數是在函式裡面宣告的,他的生命週期就跟區域變數一樣
int *f(void) { return &(int) {5}; } // 會出錯
可惜他跟vla不能混用
f( (int [n]) {5} ); // 不合法
C99之中可以指明只對某個欄位初始化,這功能稱為designated initializers
struct S a = {.y = 1}; // 反觀ANSI C只能從第一個欄位初始化
int a[100] = {[99] = 1}; // 把最後一個元素設定為1,其他都是0
int a[100] = {[99] = n}; // 把最後一個元素設定成n
int a[100] = {[n] = 5}; // 不合法
int a[n] = {[0] = 1}; // 不合法 vla 不能初始化
在ANSI C年代有個trick,如果要紀錄一筆資料,其中包含id和姓名,可以這樣設計
struct record {
int id;
char name[20];
};
但是實際上不會每個人的姓名都用到20個字,會浪費空間,所以就改用
struct record {
int id;
char *name;
};
不過這樣使用的時候需要多一次malloc,速度較慢且會造成記憶體破碎。
一種解決方法是這樣
struct record {
int id;
char name[1]; //有些編譯器寫0也可以 假設沒有padding
};
然後每次都malloc( sizeof(struct record) + strlen(name) );
就可以使整個struct都是在連續的記憶體上,只是這種方法並不被標準所保證。
在C99中則可以這樣寫
struct record {
int id;
char name[];
};
這功能被稱為flexible array members
--
※ 發信站: 批踢踢實業坊(ptt.cc)
◆ From: 140.119.162.50
推
04/11 22:49, , 1F
04/11 22:49, 1F
推
04/11 23:18, , 2F
04/11 23:18, 2F
→
04/11 23:19, , 3F
04/11 23:19, 3F
推
04/12 00:14, , 4F
04/12 00:14, 4F
推
04/12 00:14, , 5F
04/12 00:14, 5F
→
04/12 00:26, , 6F
04/12 00:26, 6F
→
04/12 05:26, , 7F
04/12 05:26, 7F
推
04/12 09:26, , 8F
04/12 09:26, 8F
→
04/12 10:28, , 9F
04/12 10:28, 9F
推
04/12 21:14, , 10F
04/12 21:14, 10F