C预处理器:如何创建字符文字?
出于好奇,我想知道是否可以定义一个可以将其参数转换为字符文字的宏:
switch(getchar()) { case MYMACRO(A): printf("Received A\n"); break; case MYMACRO(a): printf("Received a\n"); break; case MYMACRO(!): printf("Received an exclamation mark\n"); break; default: printf("Neither a nor A nor !\n"); break; }
我头脑中有两种可能的解决方案:
枚举所有字符
#define LITERAL_a 'a' #define LITERAL_b 'b' ... #define MYMACRO(x) LITERAL_ ## x
它不适用于MYMACRO(!)
因为!
不是C标识符的有效组件。
将参数转换为字符串文字
#define MYMACRO(x) #x [0]
它涉及指针取消引用,并且在诸如案例标签的地方无效。
我不是要求一种方法来“改进”上面的switch语句本身。 这只是一个玩具的例子。 重复。 这只是一个玩具的例子。
这是我可能的解决方案:
#define EVAL(...) __VA_ARGS__ #define Q() ' #define MYMACRO(...) Q()EVAL(__VA_ARGS__)Q()
(Variadic宏用于支持MYMACRO(,)
因为它将被解析为两个空参数。)
由于无法比拟,我不确定这段代码是否符合标准。 不过,我认为这段代码适用于大多数C99编译器。 但是,此代码不适用于以下字符:
-
(
必须匹配)
-
)
用于标识参数列表的开始和结束 -
'
和"
用于字符串文字和字符常量 -
\
,需要逃避 - 空白字符,因为它们不是令牌
我很确定没有适用于(
, )
, '
或'
解决方案,因为如果允许这样做,编译器就必须改变解析宏参数的方式。
虽然我无法获得user4098326的编译答案,但我确实得到了下面的解决方案来编译并按预期工作(在Code Composer Studio中)。 关键是使用符号连接运算符。 但请注意,根据标准,这不应该起作用。 单引号(’)不是有效的标记,也不是单引号后跟单个字符(’a)。 因此,那些不应该是串联运算符的输入或输出。 因此,我不建议实际使用此解决方案。
#define CONCAT_H(x,y,z) x##y##z #define SINGLEQUOTE ' #define CONCAT(x,y,z) CONCAT_H(x,y,z) #define CHARIFY(x) CONCAT(SINGLEQUOTE , x , SINGLEQUOTE ) #define DO_CASE(...) case CHARIFY(__VA_ARGS__): printf("Got a " #__VA_ARGS__ "\n"); break
然后:
switch(getchar()) { DO_CASE(A); DO_CASE(a); DO_CASE(!); default: printf("Neither a nor A nor !\n"); break; }