如何比较C条件预处理器指令中的string
我必须在C中做这样的事情。它只有在使用char时才有效,但是我需要一个string。 我该怎么做?
#define USER "jack" // jack or queen #if USER == "jack" #define USER_VS "queen" #elif USER == "queen" #define USER_VS "jack" #endif
我不认为有一种方法可以在预处理指令中完成可变长度的string比较。 你也许可以做以下事情:
#define USER_JACK 1 #define USER_QUEEN 2 #define USER USER_JACK #if USER == USER_JACK #define USER_VS USER_QUEEN #elif USER == USER_QUEEN #define USER_VS USER_JACK #endif
或者你可以重构一些代码,而不是使用C代码。
[已更新2016.01.31]
由于有些人不喜欢我以前的回答,因为它通过完成目标而避免了OP的整个compile time string compare
方面,而不需要string比较,下面是一个更详细的答案。
你不能! 不在C98或C99中。 甚至没有在C11。 没有任何数量的MACRO操纵会改变这一点。
在#if
中使用的const-expression
的定义不允许string。
它允许字符,所以如果你限制自己的字符,你可以使用这个:
#define JACK 'J' #define QUEEN 'Q' #define CHOICE JACK // or QUEEN, your choice #if 'J' == CHOICE #define USER "jack" #define USER_VS "queen" #elif 'Q' == CHOICE #define USER "queen" #define USER_VS "jack" #else #define USER "anonymous1" #define USER_VS "anonymous2" #endif #pragma message "USER IS " USER #pragma message "USER_VS IS " USER_VS
您可以! 在C ++ 11中。 如果你为比较定义一个编译时帮助函数。
// compares two strings in compile time constant fashion constexpr int c_strcmp( char const* lhs, char const* rhs ) { return (('\0' == lhs[0]) && ('\0' == rhs[0])) ? 0 : (lhs[0] != rhs[0]) ? (lhs[0] - rhs[0]) : c_strcmp( lhs+1, rhs+1 ); } // some compilers may require ((int)lhs[0] - (int)rhs[0]) #define JACK "jack" #define QUEEN "queen" #define USER JACK // or QUEEN, your choice #if 0 == c_strcmp( USER, JACK ) #define USER_VS QUEEN #elif 0 == c_strcmp( USER, QUEEN ) #define USER_VS JACK #else #define USER_VS "unknown" #endif #pragma message "USER IS " USER #pragma message "USER_VS IS " USER_VS
所以,最终,你将不得不改变你实现为USER
和USER_VS
select最终string值的目标的方式。
你不能在C99中编译时间string比较,但你可以编译时间selectstring。
如果你真的必须编译时间比较,那么你需要改变为C ++ 11或更新的变体,允许该function。
[原文如下]
尝试:
#define jack_VS queen #define queen_VS jack #define USER jack // jack or queen, your choice #define USER_VS USER##_VS // jack_VS or queen_VS // stringify usage: S(USER) or S(USER_VS) when you need the string form. #define S(U) S_(U) #define S_(U) #U
更新:ANSI令牌粘贴有时不明显。 ;-D
在一个macros之前放一个#
会导致它被改变成一个值的string,而不是原来的值。
在两个令牌之间放置一个双##
使得它们连接成一个单一的令牌。
因此,macrosUSER_VS
具有扩展jack_VS
或queen_VS
,具体取决于您如何设置USER
。
stringifymacrosS(...)
使用macros间接,所以命名macros的值被转换成一个string。 而不是macros的名字。
因此, USER##_VS
变成jack_VS
(或queen_VS
),具体取决于你如何设置USER
。
之后,当stringifymacros被用作S(USER_VS)
, USER_VS
(在这个例子中是S(USER_VS)
的值被传递到将其值( queen
)转换成string"queen"
的间接步骤S_(jack_VS)
。
如果您将USER
设置为queen
则最终结果是string"jack"
。
有关令牌串联,请参阅: https : //gcc.gnu.org/onlinedocs/cpp/Concatenation.html
对于标记string转换,请参阅: https : //gcc.gnu.org/onlinedocs/cpp/Stringification.html#Stringification
[更新2015.02.15更正错字]
使用数字值而不是string。
最后,将常量JACK或QUEEN转换为一个string,使用stringize(和/或tokenize)运算符。
如果你的string是编译时间常量(如你的情况),你可以使用下面的技巧:
#define USER_JACK strcmp(USER, "jack") #define USER_QUEEN strcmp(USER, "queen") #if $USER_JACK == 0 #define USER_VS USER_QUEEN #elif USER_QUEEN == 0 #define USER_VS USER_JACK #endif
编译器可以提前告诉strcmp的结果,并将其结果replace为strcmp,从而为您提供一个可以与预处理器指令进行比较的#define。 我不知道编译器/依赖编译器选项之间是否有任何差异,但它在GCC 4.7.2上适用于我。
编辑:进一步调查,它看起来像这是一个工具链扩展,而不是GCC扩展,所以考虑到这一点…
如上所述,ISO-C11预处理器不支持string比较。 然而,用“标记粘贴”和“表访问”可以解决用“相反值”分配macros的问题。 Jesse的简单连接/ stringifymacros解决scheme失败与gcc 5.4.0,因为string在评估连接(符合ISO C11)之前完成。 但是,它可以被修复:
#define P_(user) user ## _VS #define VS(user) P_ (user) #define S(U) S_(U) #define S_(U) #U #define jack_VS queen #define queen_VS jack S (VS (jack)) S (jack) S (VS (queen)) S (queen) #define USER jack // jack or queen, your choice #define USER_VS USER##_VS // jack_VS or queen_VS S (USER) S (USER_VS)
第一行(macrosP_()
)添加一个间接让下一行(macrosVS()
)在string化之前完成并置(请参阅为什么我需要macros的双层间接? )。 stringmacros( S()
和S_()
)来自Jesse。
这个表(macros jack_VS
和queen_VS
)比OP的if-then-else结构更容易维护,来自Jesse。
最后,下一个四行块调用函数式的macros。 最后的四行块来自Jesse的答案。
将代码存储在foo.c
并调用预处理程序gcc -nostdinc -E foo.c
得到:
# 1 "foo.c" # 1 "<built-in>" # 1 "<command-line>" # 1 "foo.c" # 9 "foo.c" "queen" "jack" "jack" "queen" "jack" "USER_VS"
产量如预期。 最后一行显示USER_VS
macros在string化之前未展开。
Patrick和Jesse Chisholm的回答使我做了以下工作:
#define QUEEN 'Q' #define JACK 'J' #define CHECK_QUEEN(s) (s==QUEEN?1:0) #define CHECK_JACK(s) (s==JACK?1:0) #define USER 'Q' [... later on in code ...] #if CHECK_QUEEN(USER) compile_queen_func(); #elif CHECK_JACK(USER) compile_jack_func(); #elif #error "unknown user" #endif
而不是#define USER 'Q'
#define USER QUEEN
也应该工作,但没有testing 也有效,可能更容易处理。
以下为clang工作。 允许显示为符号macros值比较。 #error xxx只是看看编译器真的做什么。 用#define cat(a,b)replacecat定义## b打破了一些东西。
#define cat(a,...) cat_impl(a, __VA_ARGS__) #define cat_impl(a,...) a ## __VA_ARGS__ #define xUSER_jack 0 #define xUSER_queen 1 #define USER_VAL cat(xUSER_,USER) #define USER jack // jack or queen #if USER_VAL==xUSER_jack #error USER=jack #define USER_VS "queen" #elif USER_VAL==xUSER_queen #error USER=queen #define USER_VS "jack" #endif
这很简单,我想你可以说
#define NAME JACK #if NAME == queen