[英]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_SUCCESS
, ERR_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.