2011-09-01 103 views
6

有沒有一種很好的方式來結合C99的指定初始值設定項和malloc的結果?在C99 +中組合指定的初始值設定項和malloc?

下似乎有不必要的重複:

typedef struct { 
    int a, b, c; 
} Type; 

Type *t = malloc(sizeof *t); 
*t = (Type) { 
    .a = 2, 
    .b = 3, 
    .c = 5, 
}; 

可以使用Type,並且*t從上面的代碼被刪除?

+3

如果可以,如果'malloc'返回'NULL'會發生什麼? – detly

+0

看起來像你真的想要C++。 –

+0

有趣的問題,但我不認爲有任何好的答案。就個人而言,我只會使用'calloc',接着是't-> a = 2; t-> b = 3;'...('calloc'就在那裏,以防你想離開任何成員,所以如果你知道你會明確地設置它們,你也可以使用'malloc') –

回答

5

既然你問了;)C中有一個工具可以避免顯式重複的代碼宏。這就是說我沒有看到一種不重複至少這種類型的名稱的方法。但在C++他們不能要麼,所以C是至少一樣好:)

我看到的最簡單的就是

#define DESIGNATE_NEW(T)   \ 
    memcpy(malloc(sizeof(T)),   \ 
     &(T const){ __VA_ARGS__ }, \ 
     sizeof(T)) 

這將使

Type *t = DESIGNATE_NEW(Type, 
    .a = 2, 
    .b = 3, 
    .c = 5, 
); 

這有幾個優點。

  • 它正確初始化所有成員,甚至在與0的浮法類型或指針非 標準表示架構。
  • 除了Keith的版本,它是「編碼風格」是可以接受的,因爲它只是一個看起來像初始化的表達式,任何人都應該直觀地捕獲第二個代碼片斷應該做的事情。

注意:觀察宏中的const,如果編譯器確定這是相關的,則允許摺疊複合文本的多個實例。另外,還有一種方法可以使用指示符列表可選的變體,請參閱下面的P99。

缺點是memcpy和我會更快樂與任務。其次,在使用結果之前,沒有檢查malloc的失敗,但可能會遇到一些奇怪的情況,以使代碼良好地退出。

P99我採取了稍微不同的方式。在那裏,我們總是有一類的初始化函數,像

inline 
Type* Type_init(Type* t, int a, int b, int c) { 
    if (t) { 
    *t = (Type const){ .a = a, .b = b, .c = c }; 
    } 
    return t; 
} 

其受宏觀神奇,可向爲abc提供默認參數,如果省略它們。然後你可以簡單地使用類似於

Type *t = P99_NEW(Type, 1, 2, 3); 

在你的應用程序代碼。這比較好,因爲它避免了在malloc的調用失敗時導致指針無效。另一方面,這重新向初始化者發出一個命令,所以也不完美。

+0

您的'DESIGNATE_NEW'宏最接近成爲一個慣用的解決方案。 –

1

不,這是使用指定初始值設定項的唯一方法。沒有(類型){},編譯器不知道如何驗證內容。

2

您可以使用可變宏。我不會說這是一個好主意,但它的工作原理:

#include <stdlib.h> 
#include <stdio.h> 

#define CREATE(type, ptr, ...) \ 
    type *ptr = malloc(sizeof *ptr); \ 
    if (ptr) *ptr = (type){__VA_ARGS__} 

int main(void) 
{ 
    typedef struct { 
     int a, b, c; 
    } Type; 
    CREATE(Type, t, .a = 2, .b = 3, .c = 5); 
    printf("t->a = %d, t->b = %d, t->c = %d\n", t->a, t->b, t->c); 
    return 0; 
} 

請注意,我無法使用通常的do { ... } while (0)宏定義技巧(這將創建一個新的範圍,t將不可見),所以你必須小心使用它的上下文。

就我個人而言,我覺得我對不必要的重複感到高興。

相關問題