簡體   English   中英

C程序可以根據其值確定宏標識符/枚舉名稱嗎?

[英]Can a C program determine a macro identifier/enum name based on its value?

假設我們將一些錯誤代碼定義為宏 -

#define ERR_SUCCESS 0
#define ERR_BAD_INPUT 1

...

或者作為枚舉數據類型 -

enum err_t = { ERR_SUCCESS, ERR_BAD_INPUT, ...};

其中一個id由以下函數返回 -

int foo(); /* if foo() returns 0, it means success, etc */

foo()的調用者可以確定哪個標識符/名稱(ERR_SUCCESS,ERR_BAD_INPUT,...)鏈接到int返回值?

沒有。

處理器宏,顧名思義,在編譯步驟開始之前進行預處理時解析。 在調用時,即在運行時,沒有像ERR_SUCCESSERR_BAD_INPUT等名稱的ERR_SUCCESS ,這就是為什么在運行時無法確定標識符名稱的原因。

由於enum創建了編譯時常量,因此在運行時無法獲取標識符名稱,因此Simliar推理也適用於enum

不是直接的,正如其他人指出的那樣,這些標識符在運行時不可用,但您可以使用並行的名稱列表( X宏可以幫助):

#include <stdio.h>

#define ERRS \
    X(ERR_SUCCESS) \
    X(ERR_BAD_INPUT) \
    X(ERR_MORE)

#define X(x) x,
enum err_t {ERRS};
#undef X

#define X(x) #x,
static char *err_name[] = {ERRS};
#undef X

static int foo(void)
{
    /* ... */
    return ERR_BAD_INPUT;
}

int main(void)
{
    printf("%s\n", err_name[foo()]);
    return 0;
}

輸出:

ERR_BAD_INPUT

從C99開始,Keine Lust的宏甚至可以擴展為顯式設置值:

#define X(x) x,
#define X_WITH_VALUE(x, v) x = v,

和:

#define X(x) [x] = #x,
#define X_WITH_VALUE(x, v) X(x)

最后一個功能:

char const* getName(enum E e)
{
    char const* n = e < sizeof(arr)/sizeof(*arr) ? arr[e] : NULL;
    return n ? n : "<unknown error>";
}

編輯(響應評論):顯式分配值允許引入(所需!)間隙和同義詞:

enum Flags
{
    None = 0,
    F0   = 1,
    F1   = 2,
    F2   = 4,
    F3   = 8,
    G3   = F3,
}

但這會導致數組中出現間隙,導致函數中需要空指針檢查。 如果你的枚舉值變大,那么數組可能會變得很大,所以數組解決方案可能不再合適......

這些同義詞帶來了另一個問題,請參閱Jens的回答。 問題部分得到解決,代碼確實有效,但你不一定得到最初使用的同義詞,而是總是最后定義的同義詞! 在上面的例子中,即使你在代碼中使用了F3,這也是G3。 所以你必須最后定義所需的同義詞(這對我來說似乎有點不自然......)或者你使用下面的SYNONYM宏。

一些具有數組大小的特殊情況可能會通過其他技巧來解決,例如,如果您有后續值具有更高的起始值:

#define X(x) [x - Initial] = #x,
char const* n = e < sizeof(arr)/sizeof(*arr) ? arr[e - Initial] : NULL;

有趣的是獲得以上兩個枚舉的權力:

#define X(x, p) x = (1 << p),
enum err_t {None = 0, ERRS};

char const* getName(enum E e)
{
    if(e == None)
        return S(None); // stringification macro, yet to be defined
    // check, if power of two:
    if((unsigned int) e & ((unsigned int) e - 1))
    {
        int index = log2(e);
        if(index < sizeof(arr)/sizeof(*arr)
            return arr[index];
    }
    return "<unknown>";
}

兩個檢查的力量來自Sean Eron Anderson這里確切地說 ),你找到了很好的解決方案來計算log2,例如這個

完全不同的方法,適用於任何類型的不同值(但需要明確處理同義詞!):

#define X(x) x,
#define X_WITH_VALUE(x, v) x = v,
#define SYNONYM(y, x)      y = x,

#define X(x) case x: return #x;
#define X_WITH_VALUE(x, v) X(x)
#define SYNONYM(y, x)
char const* getName(enum E e)
{
    switch(e)
    {
        ERRS
        default:
            return "<unknown>";
    }
}

不會 。當您意識到從值到名稱的映射不是雙射的時,這很容易看出。 這是一種花哨的方式來表示宏等

#define ZERO   0
#define ZILCH  0
#define NADA   0
#define NIENTE 0

被允許共存。 給定0,這是相關名稱?

相同的參數適用於enum標識符。

不,編譯器不支持它。 編譯器獲取C預處理器的輸出,其中#defines由值替換。 您需要檢測代碼中的值。 比如喜歡這個問題

暫無
暫無

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

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