2011-03-18 37 views
10

我一直在思考的方式來驗證類型C宏,到目前爲止,我想出最好的辦法是這樣的:如何在C宏驗證類型

#define ASSERT_PTYPE(TYPE, VALUE) (0 && (*(int (*)(TYPE*))0)(VALUE)) 

這顯然需要一個類型名稱和指向該類型的指針。類似的ASSERT_TYPE宏也可以被創建。這似乎與海灣合作委員會工作得很好。它甚至在類型不匹配的情況下給出非常有用的錯誤消息。問題是,我不完全確定這是有效的C還是此事的最佳方式。

據我所知,標準說你可以投一個函數指針,但調用該函數指針的結果是未定義的。在這種情況下,在運行時調用函數是不可能的。這是否足夠好或者標準是否意味着您甚至無法編寫無法調用的調用cast函數的代碼?

+0

不錯的問題,這裏是一個可能的C++對應http://stackoverflow.com/questions/5237163/how-does-the-following-code-work – JoeSlav 2011-03-18 09:01:06

+0

問題是...什麼樣的情況存在於C程序員的地方不知道傳遞給該宏的類型?代碼有什麼用處?此外,這些解決了與C語言中的許多隱式類型轉換相關的任何問題。就C而言,例如,有符號和無符號是兼容的。 – Lundin 2011-03-18 12:43:10

回答

7

隨着C99和複合文字,你可以這樣做

#define ASSERT_TYPE(TYPE, VALUE) ((TYPE){ 0 } = (VALUE)) 

這確保了VALUE是分配給TYPE兼容。由於賦值,表達式返回一個右值。

複合文字在函數範圍以及文件範圍內工作,任何體面的編譯器都應該優化創建的額外對象。

加成TYPE在該宏可以是任何有效類型名稱,e.g指針double*,結構或聯合struct toto,除了陣列。陣列類型(如double[4])因分配而不起作用。使用指針 陣列double(*)[4]代替,e.g如

double A[4]; 
(*ASSERT_TYPE(double(*)[4], &A)) 

,其中第二線是再次double[4]類型的左值是編譯時檢查該屬性。

+0

它不應該讀'(TYPE *){0}',因爲他想斷言'VALUE'具有類型_pointer_到'TYPE'(宏的名字是'ASSERT_PTYPE'而不是'ASSERT_TYPE')? – Curd 2011-03-18 09:48:32

+0

@Curd,不,建議的解決方案適用於任何類型,不僅指針類型。我將其更名爲'ASSERT_TYPE'以使其更清晰。要使用它作爲指針類型,你只需要將這樣的指針類型作爲第一個參數,比如'double *'或其他類型。 – 2011-03-18 12:27:27

+0

這正是我想要得到的。這裏唯一的缺點是錯誤信息稍微偏離了你從僞函數調用中獲得的那一點。另外,在他的使用示例中,我認爲你的意思是宏返回的右值不是左值嗎? – ltc 2011-03-18 20:34:07