如何比较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 

所以,最终,你将不得不改变你实现为USERUSER_VSselect最终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_VSqueen_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_VSqueen_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_VSmacros在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