As some didn't like my earlier answer because it 避免 the whole compile time string compare aspect of the OP by accomplishing the goal with no need for string compares, here is a more detailed answer.
你不能!C98和 C99都没有。连 C11都没有。任何宏操作都不会改变这一点。
The definition of const-expression used in the #if does not allow strings.
它确实允许使用字符,所以如果你限制自己使用字符,你可以使用:
#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中。如果你为比较定义了一个编译时助手函数。
[2021.01.04: CAVEAT: This does not work in any MODERN compiler. See comment by @Artyer.]
// 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选择最终字符串值的方式。
在 C99中不能进行编译时字符串比较,但是可以选择编译时字符串。
如果您真的必须进行编译时的刺比较,那么您需要更改为 C + + 11或更新的允许该特性的变体。
[原始答案跟随]
试试:
#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
如前所述,ISO-C11预处理器支持 没有字符串比较。然而,分配具有“相反值”的宏的问题可以通过“令牌粘贴”和“表访问”来解决。Jesse 的简单 concatenate/stringify 宏解决方案在 gcc 5.4.0中失败,因为字符串化完成了 之前对串联的评估(符合 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)
但是如果用户只是 JACK 或者 QUEEN 或者 Joker 或者其他什么的,你 可以就会这样做。
有两个技巧可以使用:
令牌拼接,通过连接其字符将一个标识符与另一个标识符组合在一起。这允许您与 JACK 进行比较,而不必与某些东西进行 #define JACK比较
variadic macro expansion, which allows you to handle macros with variable numbers of arguments. This allows you to expand specific identifiers into varying numbers of commas, which will become your string comparison.
So let's start out with:
#define JACK_QUEEN_OTHER(u) EXPANSION1(ReSeRvEd_, u, 1, 2, 3)
While the pre-processor is very limited with respect to strings, most compilers know a lot about strings 在编译时也是如此. For instance this can successfully compare __BASE_FILE__ and __FILE__ at compile-time:
const int zero_div_warning __attribute__((unused)) =
42 / !strcmp(__FILE__ , __BASE_FILE__);
Compilation of this with gcc -Wno-div-by-zero -Werr succeeds when found in a .c file and fails when found in a .h file (static inline function)
我知道从技术上来说这并不能回答 OP 的问题,但是通过看上面的答案,我意识到(从我所能理解的)在预处理器中进行字符串比较并不是一种简单的方法,除非借助一些“技巧”或者其他编译器特有的魔法。因此,在重新考虑我的情况时,我意识到实际上只有一组固定的字符串可以与之进行比较,因为预处理器无论如何都必须使用静态字符串。因此,它更多的是一个风格的东西,能够比较在您的代码中的“字符串”之类的东西。因此,我决定添加一些定义,它们的语法类似于字符串(在读取它时) ,但只是整数的定义,看起来就像其他人建议的那样。例如:
#if USER == USER_JACK
// do something
#elif USER == USER_QUEEN
// do something else
#elif USER == USER_KING
// do something completely different
#else
// abort abort
#end
So now it is just a question of setting up the definitions appropriately.
So while technically this solution isn't comparing strings, syntactically it kind of behaves/looks the same.
I'm also thinking that the the SetupCereal.cmake could be further generalized to encapsulate the setup in a function, so it could be used in other situations where you want to define similar types of definitions.
> clang-7 -pthread -lm -o main main.c
main.c:10:9: warning: MYMACRO is: ('t','e','s','t')
[-W#pragma-messages]
#pragma message( "MYMACRO is: " XSTR(MYMACRO) )
^
main.c:12:9: warning: IS TRUE [-W#pragma-messages]
#pragma message( "IS TRUE" )
^
2 warnings generated.
> ./main
Hello, world!
>
如果我把条件改成:
#if MYMACRO==OTHER_STR
然后重新编译,输出结果是:
> clang-7 -pthread -lm -o main main.c
main.c:10:9: warning: MYMACRO is: ('t','e','s','t')
[-W#pragma-messages]
#pragma message( "MYMACRO is: " XSTR(MYMACRO) )
^
main.c:14:9: warning: IS FALSE [-W#pragma-messages]
#pragma message( "IS FALSE" )
^
2 warnings generated.
> ./main
Hello, world!
>
So, if the tested macro and the value macros are defined as lists of character values, then they can be compared directly in a preprocessor #if conditional - and in order to print such macros in a pragma message, use of stringifying macros are required.