2015-09-25 82 views
0

是否可以在宏中進行無效性檢查和訪問?C99結構體成員訪問的宏擴展

如:

#define LOG(mystruct, severity, format, ...) ({ \ 
    severity_t current = ERROR; \ 
    if (mystruct) { \ 
    current = mystruct->error_level; \ 
    } \ 
    if (severity >= current) { \ 
    ... //handle logging 
    } \ 
}) 

如果我把這個與LOG(NULL, DEBUG, "test %s", "one");我得到一個錯誤這樣:

error: member reference base type 'void' is not a structure or union note: expanded from macro 'LOG' current = mystruct->error_level;

MYSTRUCT被定義爲:

typedef struct mystruct_t { 
    severity_t error_level; 
} 

我想允許使用NULL的可能性。例如:創建結構本身時發生錯誤的情況。

+0

NULL-> error_level'不可編譯。也許你可以使用'MYSTRUCT * ptr =(severity);'然後'if if(ptr)current = ptr-> error_level;' –

+0

內聯函數會更整齊 –

+0

讓我稍微說明一下結構。 'mystruct_t'是一個超結構,它包含'severity_t'。我想允許爲'mystruct'處理NULL的可能性(例如:在創建'mystruct_t'本身時發生錯誤時) – bge0

回答

3

您的問題是,雖然第一個分支將永遠不會被採用,但NULL沒有正確的類型來執行->error_level

您可以通過給它正確的類型來避免這種情況。我會用一個局部變量來做到這一點,而不是一個強制轉換,所以你會捕獲你的宏的錯誤用例。只需加上

yourType* myStr = mystruct; 
current = myStr->error_level; 

你應該沒問題。

0

是否可以在宏中進行無效性檢查和訪問?

不,預處理器正在做簡單的文本替換。它不支持宏定義內的條件。

當您使用宏與LOG(NULL, DEBUG, "test %s", "one");,第四行擴展到

current = NULL->error_level; 

而且由於NULL通常被定義爲#define NULL ((void *)0),進一步擴展到

current = ((void *)0)->error_level; 

這就是爲什麼你得到的有關void的消息不是結構或聯合。


要解決該問題,不傳遞NULL到宏,傳遞一個包含NULL到宏指針,例如

mystruct_t *ptr = malloc(...); 
if (!ptr) 
    LOG(ptr, DEBUG, "no memory");