2017-04-11 43 views
3

我想寫一些C可重用的通用型安全的代碼,使用宏,類似於如何klib作品:簡單定義多行C宏的技巧?

#define Fifo_define(TYPE) \ 
    \ 
    typedef struct { \ 
     TYPE *head; \ 
     TYPE *tail; \ 
     size_t capacity; \ 
    } Fifo_##TYPE, *pFifo_##TYPE; \ 
    \ 
    inline Fifo_##TYPE * Fifo_##TYPE##_init(size_t capacity) { \ 
     Fifo_##TYPE * fifo = calloc(1, sizeof(Fifo_##TYPE)); \ 
     TYPE * data = calloc(capacity, sizeof(TYPE)); \ 
     fifo->head = data; \ 
     fifo->tail = data; \ 
     fifo->capacity = capacity; \ 
    } 

// define macros  

#define Fifo(TYPE) Fifo_##TYPE 
#define Fifo_init(TYPE, capacity) Fifo_##TYPE_init(capacity) 

然後,我只是與任何類型的參數一起使用:

Fifo_define(int32_t); 
... 
Fifo(int32_t) *myFifo = Fifo_init(int32_t, 100); 

然而,寫這個是相當複雜和容易出錯,沒有IDE編輯器支持(智能感知),所以我想知道是否有任何技巧可以讓我(可能)添加一些定義,然後包括文件,而不必結束每行\

喜歡的東西:

// no idea how to do this, just checking if similar concept is possible 

#define FIFO_TYPE int 
#define FIFO_NAME Fifo_int 

#include <generic-fifo.h> 

#undef FIFO_NAME 
#undef FIFO_TYPE 

,我會以某種方式得到了所有正確的struct S和功能。問題是這些宏中有很多參數串聯,所以我不確定這是否可以以比第一個片段更簡單的方式完成?

+1

我估計這是可能的,我已經看到了這種宏觀魔法。但是,您聲明(改述)您希望減少以「\」結尾的行數,並且我理解這是對可讀性的(值得稱讚的)期望。我也認爲會有副作用,例如需要使用「#undef」。 (我有一個使用undef的迷信是邪惡的,即容易出現用法錯誤。)我估計宏觀魔法不會使事情更具可讀性,相反。 – Yunnosch

回答

1

並不推薦在這種情況下,但你可以做這樣的事情,你想達到與X-macros什麼:

#define SUPPORTED_TYPES \ 
    X(int)    \ 
    X(double)    \ 
    X(char) 

#define X(TYPE)   \ 
    typedef struct {  \ 
     TYPE *head;  \ 
     TYPE *tail;  \ 
     size_t capacity; \ 
    } Fifo_##TYPE, *pFifo_##TYPE; 
SUPPORTED_TYPES 
#undef X 

#define X(TYPE)           \ 
inline Fifo_##TYPE * Fifo_##TYPE##_init(size_t capacity) \ 
{              \ 
    Fifo_##TYPE * fifo = calloc(1, sizeof(Fifo_##TYPE)); \ 
    TYPE * data = calloc(capacity, sizeof(TYPE));   \ 
    fifo->head = data;          \ 
    fifo->tail = data;          \ 
    fifo->capacity = capacity;        \ 
} 
SUPPORTED_TYPES 
#undef X 

但這並沒有真正改善的情況所有的東西。它擺脫了單一,醜陋的宏的需求,所以你可以分成幾個部分的代碼。但宏觀的混亂依然存在。


我會推薦一些完全不同的方法。兩條建議:

  • 在運行時以經典的C方式處理類型泛型的東西。使用回調。如果需要,使用枚舉跟蹤使用的類型。

  • C11 _Generic允許各種類型的安全技巧,並可用於逐步淘汰這些凌亂的宏。 Example that implements "functors"。宏本身保持最小化,並且輸入了各種類型的不同實現。 (這通常是你最終做無論如何,當你做類型泛型編程。)

1

如果您正在使用複雜的宏,可以考慮使用的不是C預處理器M4。 m4 is similar to the C pre-processor but is much more powerful並且可以做像沒有續行字符的多行。

使用類似m4的代碼生成器稱爲meta-programming

% grep -v '#include' file1 file2 | m4 > outfile 
% m4 file1 file2 | cc 

由於在基本水平,將在一個類似的方式M4作品到C預處理器:

在C使用M4可以通過將其作爲預預處理器like this來實現除了支持自己的高級功能之外,通常還可以正確地轉換任何普通的C宏。