【问题标题】:C preprocessor: How to create a character literal?C 预处理器:如何创建字符文字?
【发布时间】:2016-02-20 15:59:55
【问题描述】:

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

 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 语句本身的方法。这只是一个玩具示例。重复。这只是一个玩具示例。

【问题讨论】:

  • 我认为你的问题不是自洽的。首先,您要求一种使用宏“创建字符文字”的方法。然后您提出一个可能的解决方案,但它根本不会创建字符文字,而只会为您提供一个 char 值。您应该调整标题以实际表达您的追求。 “将x转换为等于'x'的编译时间值”?或者,您可以将“可能的解决方案”称为“尝试的解决方法”,但这取决于您所追求的。
  • 有一个名为 charizing 的 Microsoft 特定解决方案:msdn.microsoft.com/library/91tt6dfs%28v=vs.110%29.aspx。但是,如果您需要符合标准,恐怕您会迷失方向。
  • 即使使用像@ctx 指向的非标准扩展名,非部分函数显然也是不可能的,因为空格不是标记。无论如何,标准 C 并没有提供解决方案。
  • 对于它的价值,#define MYMACRO(x) 'x' 在指定 -traditional 标志时在 GCC 中工作。这将排除所有现代宏定义,例如可变参数宏。 (我属于那些认为 'x' 足以表达字符文字的人的阵营。)
  • @Ctx:当我指定--traditional 时,我只是再次尝试确定。 (这个answer on the C FAQ让我尝试了。)

标签: c macros c-preprocessor


【解决方案1】:

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

【讨论】:

  • ICC 不会抱怨这一点,但 gcc 和 clang 会这样做,任何想法都需要哪些特定的 -Wno-* 选项来关闭“丢失的终止”......已经添加了 -Wno-multichar摆脱了多字符常量警告,但不幸的是-Wno-cpp 只消除了#warning 指令......所以目前使用-Wp,-w......假设在预处理器中也会发出警告的任何东西都会在编译器中发出警告(除了#warning 当然可以,但是 -Wp,-w,-Wcpp 并没有像你想象的那样工作)
  • @technosaurus 不幸的是,你的猜测比我的好。我的工作系统上只有 CCS。鉴于这个解决方案违反了标准,当然没有任何标志会让人满意。
【解决方案2】:

这是我可能的解决方案:

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

(可变参数宏用于支持MYMACRO(,),因为它会被解析为两个空参数。)

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

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

我很确定没有适用于()'" 的解决方案,因为如果允许这样做,编译器将不得不更改宏参数的解析方式。

【讨论】:

  • gcc -std=c99 -pedantic-errors 验证这不符合标准,section 6.4p2 解释了为什么无法提出符合标准的解决方案。
  • 我今天刚测试了这段代码,发现虽然展开结果类似于字符常量,但编译器无法识别,所以像char a=MYMACRO(a);这样的完整程序无法编译。跨度>
  • 编译的词法分析阶段发生在编译的宏替换阶段之前。
  • "[...] 所以像 char a=MYMACRO(a); [...]" 这样的完整程序哈哈。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-06-18
  • 2012-02-16
  • 1970-01-01
  • 2011-11-28
  • 2010-11-25
  • 1970-01-01
相关资源
最近更新 更多