C 预处理器:如何创建字符文字?

问题描述 投票:0回答:3

出于好奇,我想知道是否可以定义一个宏来将其参数转换为字符文字:

 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]

它涉及指针取消引用,并且在 case 标签等地方无效。

我并不是在寻求一种“改进”上述 switch 语句本身的方法。 这只是一个玩具示例。 重复。 这只是一个玩具示例。

c macros c-preprocessor
3个回答
5
投票

虽然我无法得到 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;
 }

2
投票

这是我可能的解决方案:

#define EVAL(...) __VA_ARGS__
#define Q() '
#define MYMACRO(...) Q()EVAL(__VA_ARGS__)Q()

(可变参数宏用于支持

MYMACRO(,)
,因为它会被解析为两个空参数。)

由于不匹配的

'
,我不确定此代码是否符合标准。 不过,我认为这段代码适用于大多数 C99 编译器。 但是,此代码不适用于以下字符:

  • (
    必须与
    )
  • 匹配
  • )
    用于标识参数列表的开始和结束
  • '
    "
    用于字符串文字和字符常量
  • \
    ,需要转义
  • 空白字符,因为它们不是标记

我相当确定没有适用于

(
)
'
"
的解决方案,因为如果允许这样做,编译器将不得不更改解析宏参数的方式。


0
投票

Microsoft 有 charizing 运算符

#@
但这是特定于编译器的。我发现
*#
在 VS 和 gcc 中都有效(可能还有更多),但我一辈子都不记得我从哪里得到它了。

#define MAKECHAR(x)  *#x

导致声明

a = MAKECHAR(b);

扩大为

a = 'b';
© www.soinside.com 2019 - 2024. All rights reserved.