2014-01-26 46 views
2

有沒有一種方法可以生成一個產生數據類型列表的最大大小的宏?GCC Preproccesor宏來確定多個結構的最大大小

目標

typedef struct { 
    uint8_t x; 
} A; 

typedef struct { 
    uint16_t x; 
} B; 

typedef struct { 
    uint8_t x[10]; 
} C; 

#define sizeof_max(A,B,C) //compiles to '10' 

使用案例

不同的值,映射爲一個共同的數據段。

typedef union { 
    uint8_t array[sizeof_max(A,B,C)]; 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; //and someday down the road 'D' may also get added 
} DATA_SEG; 

這是用於設備實現基本協議ISO_HUGENUM_A的嵌入式應用程序。該設備還必須支持對該協議EXT_A0,EXT_A1,EXT_B0的擴展。哎呀,在這種情況下,EXT_C0真的有機會出現在路上(yuck)!

注意

這裏的主要目標是爲頂級系統知道在一個可擴展和安全的方式將數據段的大小。當你需要陣列時,只需要說'作爲陣列''就很有誘惑力。但

  • 在系統級(誰不提供有關該協議的EFF)有讀,寫和檢查(例如CRC)這個數據段

  • 2歲下山的路「 EXT_C0'可能會出現。我要離開這個可憐的靈魂誰繼承了我的代碼的東西時EXT_C0增長的數據段

我希望有一個解決方案,不會打破,但還沒有找到一個還沒有。有任何想法嗎?所有尺寸都將由預處理器生成,所以它看起來像是宏的理想候選者。

-Justin

+1

爲什麼你不能只使用'sizeof'一些'union',就像你的'DATA_SEG' *沒有*'array'一樣? –

+2

這不就是'union'的正常用例嗎? –

+0

刪除了C++標籤;謝謝。 –

回答

3

下面的宏定義不準確有問:

#define sizeof_max(s1,s2,s3) sizeof(union{s1 a; s2 b; s3 c; }) 

對於示例結構如下:

size_t s = sizeof_max(A,B,C) ; 

結果s = 10。

當然,你可以省略數組成員,只是蒙上了DATA_SEG對象地址爲uint8_t*,當你要訪問的字節數組:

DATA_SEG x ; 
uint8_t* array = (uint8_t*)&x ; 

這將使如果有必要DATA_SEG添加更多的結構,而無需改變宏 - 更安全,更可維護。


新增

另一種可能性是專業的解釋從字節覆蓋從而分離:

typedef union 
{ 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; 
    D added_someday ; 
} DATA_SEG_U; 

typedef union 
{ 
    uint8_t array[sizeof(DATA_SEG_U)]; 
    DATA_SEG_U data_seg ; 
} DATA_SEG ; 
+0

「* //並且總有一天'D'也可能被添加*」:OP要求進行概括,而不僅僅針對3個成員的情況。 – pablo1977

+0

@ pablo1977:我得考慮一下。 – Clifford

+0

我只是在想這個;當你克利福!非常優雅的解決方案。謝謝。 –

0

結合複雜的宏具有多級預處理可以工作 -

這實現了「最多5個輸入」的預期目標。

#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N 

#define VA_NUM_ARGS(...)     VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1) 
#define macro_dispatcher__(func,nargs) funC## nargs 
#define macro_dispatcher_(func, nargs) macro_dispatcher__(func, nargs) 
#define macro_dispatcher(func, ...)  macro_dispatcher_(func, VA_NUM_ARGS(__VA_ARGS__)) 

#define sizeof_max(...) macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__) 

#define sizeof_max1(a)   (sizeof(a)) 
#define sizeof_max2(a,b)  (sizeof(a)>sizeof(b)?sizeof(a):sizeof(b)) 
#define sizeof_max3(a,b,c)  sizeof_max2(sizeof_max2(a,b), c) 
#define sizeof_max4(a,b,c,d) sizeof_max2(sizeof_max3(a,b,c),d) 
#define sizeof_max5(a,b,c,d,e) sizeof_max2(sizeof_max4(a,b,c,d),e) 

這將爲GCC/C99工作。這是問題的解決方案,我在這裏發帖是因爲我從中學到了很多東西,並且想分享它。這就是說,閱讀免責聲明結束:)。

參考

使用macro_dispatcher的()由 'RMN' 從efesx論壇在這裏提供:

添加FCN#函數名也描述在這裏:

當然,這裏有一些GCC可變參數宏網頁:

typedef union { 
    uint8_t array[sizeof_max(A,B,C)]; //array is of size 10. 
    A iso_hugenum_a; 
    B ext_a0; 
    C ext_a1; 
} DATA_SEG; 

擊穿

你可以嘗試在 'main.c中' 這個代碼,選擇 'GCC-E的main.c' 編譯觀察宏觀內斯:

int main (void) { 
    uint8_t rslt; 

    //preprocs to 'rslt=C;' 
    rslt = VA_NUM_ARGS_IMPL(A,B,C,A,B,C,A); 

    //preprocs to 'rslt=3' 
    rslt = VA_NUM_ARGS(A,B,C); 

    //preprocs to 'rslt=maxN' 
    rslt = macro_dispatcher__(max, N); 

    //preprocs to 'rslt=macro_dispatcher_(max, N);' 
    rslt = macro_dispacther_(max, N); 

    //preprocs to 'rslt=max3;' 
    rslt = macro_dispatcher(max, X, Y, Z); 

    //preprocs to 'sizeof_max1(A)/max2(A,B)/max3(A,B,C)' 
    rslt = sizeof_max(A); 
    rslt = sizeof_max(A,B); 
    rslt = sizeof_max(A,B,C); 


    //Breakdown: 
    //sizeof_max(A,B,C); 
    //macro_dispatcher(sizeof_max, __VA_ARGS__)(__VA_ARGS__) 
    //macro_dispatcher_(sizeof_max, 3)(__VA_ARGS__) 
    //macro_dispatcher__(sizeof_max,3)(__VA_ARGS__) 
    // 
    //Result: 
    //sizeof_max3(__VA_ARGS__) 
    //sizeof_max3(A,B,C) 
    rslt = sizeof_max(A,B,C); 

    return 0; 
} 

(免責聲明)更簡單&更安全永遠贏。因此,我很可能會選擇離克利福德最近的答案。沒有必要讓我玩一些可愛的技巧,這些技巧會讓其他人「一字不漏」。