簡體   English   中英

不同情況下C宏的不同行為

[英]Different behaviour of C macro for different cases

這是代碼,

#include<stdio.h>
#include<stdbool.h>

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))                                                               

struct my_struct {
    int a, b;
//  char c;
};

int main() {
    bool cond = 1;
    BUILD_BUG_ON((sizeof(struct my_struct) % 8) != 0);
    BUILD_BUG_ON(cond);
    return 0;
}

第一次使用BUILD_BUG_ON(條件)宏如果sizeof struct不等於8則拋出編譯錯誤,因為條件將評估為true。 但即使我提供真實條件,第二次使用宏也不會拋出編譯錯誤。 我無法理解這種行為。 誰能解釋一下?

BUILD_BUG_ON在實現編譯時斷言。

給定一個可以在編譯時計算的參數,如果參數為非零(true),則會導致編譯時失敗,如果參數為非零(false)則不會執行任何操作。

它不適用於在運行時計算的參數。

#define BUILD_BUG_ON(condition) ((void)sizeof(char[1 - 2*!!(condition)]))

!! 是兩個合乎邏輯的“非”運營商; 它們具有將值0歸一化為0 ,將任何非零值歸一化為1

如果結果條件為1 (真),則1 - 2*!!(condition)值為-1 如果條件為0 (假),則值為1

數組可能沒有負(或零)大小。 一些編譯器可能支持零長度數組作為擴展; 這個宏確保即使是這樣的編譯器也能診斷出錯誤。 如果size是常量表達式,則具有負大小的數組是違反約束的,需要編譯時診斷。

如果表達式為false,則沒有錯誤; 宏擴展為一個什么都不做的表達式。 如果表達式為true 且是常量表達式 ,則宏的擴展嘗試定義負大小的數組,從而導致編譯時錯誤。

如果表達式不是常量,則宏不起作用。 C(C99和更高版本)允許可變長度數組 (VLA)。 不允許零或負長度的VLA,但是通常不能在編譯時檢測到定義這樣的VLA。 它是未定義的行為 - 在這種情況下,它可能什么都不做。 (只是為了使文件范圍內不允許使用VLA。)

理想情況下,宏應附有解釋如何使用它的文檔。 該文檔應該解釋該參數必須是編譯時表達式。

底線:您應該只將此宏與常量表達式參數一起使用。 (要測試運行時表達式,可以使用assert() 。)如果使用值為零的非常量表達式,則行為未定義; 最可能的結果是預期的“斷言”不會觸發,並且不會檢測到錯誤。

我認為你的方法完全不自然。
這是糟糕的代碼,即使它會起作用。
您可以嘗試更自然的方法來處理錯誤。

斷言

assert在運行時測試條件,並在測試失敗時顯示錯誤消息。

 #include <assert.h>
 int main(void)
 {
     assert((sizeof(struct my_struct) % 8) != 0);
 }

static_assert

在C11投訴編譯器中, static_assert(condition, "Error message")執行常量表達式所需的操作:

static_assert((sizeof(struct my_struct) % 8) != 0, "Wrong struct");  

#if和#error

也可以使用#if#error編譯器指令,但在這種情況下我不建議你,因為#if不理解sizeof

語法是:

#if some_condition // Put an integer constant expression readable by an #if.
#  error This is wrong.
#endif

這三種方法中的一些必須滿足您的需求。

更改

BUILD_BUG_ON(cond);

BUILD_BUG_ON(1);

獲得預期的行為。

cond值僅在運行時可用時,將在未優化的構建中生成計算所需sizeof的代碼(並將其結果丟棄),或者在優化的構建中完全忽略整個表達式。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM