看板 C_and_CPP 關於我們 聯絡資訊
下面是我以前學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
VictorTom:學程式真是永無止盡啊, 就算只看C/C++兩套語言也是Orz 04/11 22:49
yauhh:那函數可以傳回compound literal嗎? 04/11 23:18
yauhh: 嗯...應該說可傳回"compund value"嗎? 04/11 23:19
LPH66:樓上的問題等於問說能不能回傳一個 struct 那答案就很明顯了 04/12 00:14
softwind:原來那個 char [0] 是這樣來的... 一直沒有搞懂過 04/12 00:14
yauhh:不盡相同,隨便return {1,'a'},回主程式能(struct S)嗎? 04/12 00:26
LPH66:唔? 不是有 struct S A = func(); 這種寫法嗎? 04/12 05:26
ledia:我猜測不能是因為會認不得是一個 type value 04/12 09:26
FRAXIS:所以加上強迫轉型就可以了吧.. 04/12 10:28
yoco315:什麼時候才有要語法層支援的 tuple XD 04/12 21:14