linking運作流程 - toolchain教學




C編譯器斷言-如何實現? (7)

以下COMPILER_VERIFY(exp)宏工作得很好。

// combine arguments (after expanding arguments)
#define GLUE(a,b) __GLUE(a,b)
#define __GLUE(a,b) a ## b

#define CVERIFY(expr, msg) typedef char GLUE (compiler_verify_, msg) [(expr) ? (+1) : (-1)]

#define COMPILER_VERIFY(exp) CVERIFY (exp, __LINE__)

它適用於C和C ++,可以在任何允許使用typedef的地方使用。 如果表達式為true,則為1 char的數組生成typedef(這是無害的)。 如果表達式為false,則為-1個字符的數組生成typedef,這通常會導致錯誤消息。 作為arugment給出的表達式可以是任何求值為編譯時常量的表達式(因此涉及sizeof()的表達式可以正常工作)。 這使它比它更靈活

#if (expr)
#error
#endif

您可以將其限制為可由預處理器評估的表達式。

我想在錯誤情況下實現一個“斷言”來阻止編譯,而不是在運行時失敗。

我目前有一個像這樣的定義,它工作得很好,但它增加了二進製文件的大小。

#define MY_COMPILER_ASSERT(EXPRESSION) switch (0) {case 0: case (EXPRESSION):;}

示例代碼(無法編譯)。

#define DEFINE_A 1
#define DEFINE_B 1
MY_COMPILER_ASSERT(DEFINE_A == DEFINE_B);

我如何實現它,以便它不生成任何代碼(為了最小化生成的二進製文件的大小)?


使用'#error'是一個有效的預處理器定義,導致編譯在大多數編譯器上停止。 你可以這樣做,例如,為了防止在調試中編譯:


#ifdef DEBUG
#error Please don't compile now
#endif

如果你的編譯器像DEBUG或NDEBUG那樣設置一個預處理器宏,你可以做這樣的事情(否則你可以在Makefile中設置它):

#ifdef DEBUG
#define MY_COMPILER_ASSERT(EXPRESSION)   switch (0) {case 0: case (EXPRESSION):;}
#else
#define MY_COMPILER_ASSERT(EXPRESSION)
#endif

然後,您的編譯器僅針對調試版本進行斷言。


我在C中的靜態斷言中找到的最佳寫法是pixelbeat 。 請注意,靜態斷言正被添加到C ++ 0X中,並且可能會進入C1X,但這不會有一段時間。 我不知道我給出的鏈接中的宏是否會增加二進製文件的大小。 我懷疑他們不會,至少如果你在合理的優化水平上編譯,但你的里程可能會有所不同。


我知道你對C感興趣,但看看boost的C ++ static_assert 。 (順便說一句,這很可能在C ++ 1x中可用。)

我們為C ++做了類似的事情:

#define COMPILER_ASSERT(expr)  enum { ARG_JOIN(CompilerAssertAtLine, __LINE__) = sizeof( char[(expr) ? +1 : -1] ) }

這顯然只適用於C ++。 pixelbeat討論了一種修改它以便在C中使用的方法。


正如Leander所說,靜態斷言正在被添加到C ++ 11中,現在他們已經有了。

static_assert(exp, message)

例如

#include "myfile.hpp"

static_assert(sizeof(MyClass) == 16, "MyClass is not 16 bytes!")

void doStuff(MyClass object) { }

請參閱上面的cppreference頁面


編譯最終二進製文件時,將MY_COMPILER_ASSERT定義為空白,以使其輸出不包含在結果中。 只能按照調試方式定義它。

但實際上,你不可能以這種方式捕捉每一個斷言。 有些在編譯時沒有意義(就像斷言值不為null)。 您所能做的就是驗證其他#defines的值。 我不確定你為什麼要那樣做。





assertions