【问题标题】:Is it possible to convert a C string literal to uppercase using the preprocessor (macros)?是否可以使用预处理器(宏)将 C 字符串文字转换为大写?
【发布时间】:2012-09-09 10:51:16
【问题描述】:

忽略有时有更好的非宏方法可以做到这一点(遗憾的是,我有充分的理由),我需要使用宏编写一大堆通用代码。本质上是一个宏库,可为某些预先指定的类型生成大量函数。

为避免破坏大量预先存在的单元测试,库必须做的一件事是,对于每种类型,生成该类型的名称以全部大写进行打印。例如。类型“flag”必须打印为“FLAG”。

我可以手动为每种类型写出常量,例如

#define flag_ALLCAPSNAME FLAG

但这并不理想。我希望能够以编程方式执行此操作。

目前,我已经一起破解了这个:

char capname_buf[BUFSIZ];
#define __MACRO_TO_UPPERCASE(arg) strcpy(capname_buf, arg); \
 for(char *c=capname_buf;*c;c++)*c = (*c >= 'a' && *c <= 'z')? *c - 'a' + 'A': *c;
__MACRO_TO_UPPERCASE(#flag)

它在某种程度上做了我想要的(即在这段代码之后,capname_buf 的内容为“FLAG”),但我更喜欢一个允许我使用宏定义字符串文字的解决方案,避免需要这个愚蠢的缓冲区。

我不知道该怎么做,但也许我遗漏了一些明显的东西?

我编写了一个可变参数 foreach 循环宏(如 this one),但我不能改变由#flag 生成的字符串文字的内容,而且无论如何,我的循环宏需要一个字符指针列表迭代(即迭代列表,而不是索引等)。

想法?

【问题讨论】:

  • @unwind 我看到了,但答案不正确(因此没有用)b/c 它假设你不能在预处理器中进行循环(你可以)。
  • 怎么样?您的示例没有显示使用预处理器完成的循环,如果您知道该怎么做,那不应该是您起点的一部分吗?
  • 可能一个重要的限制是 C 宏无法将标记拆分为更小的标记,只能粘贴或字符串化它们以生成更大的标记。所以预处理器不能作用于你的类型名称flag 的单个字符。但是,除了标准要求之外,还有其他(更强大的)C 预处理器可用。

标签: c macros c-preprocessor


【解决方案1】:

在可移植的 C99 中不可能有一个将常量字符串转换为所有大写字母的宏(特别是因为字母的概念与字符编码有关。UTF8 字母与 ASCII 字母不同)。

但是,您可以考虑其他一些解决方案。

  • 自定义您的编辑器以执行此操作。例如,您可以编写一些 emacs 代码,根据需要更新每个 C 源文件。

  • 在你的 C 源代码上使用一些预处理器(也许是一个简单的 C 代码生成器脚本,它会在一些 #include-d 文件中发出一堆 #define)。

  • 使用GCC extensions或许有

    #define TO_UPPERCASE_COUNTED(Str,Cnt)
    #define TO_UPPERCASE(Str) TO_UPPERCASE_COUNTED(Str,__COUNT__) {( \
       static char buf_##Cnt[sizeof(Str)+4]; \
       char *str_##Cnt = Str; \
       int ix_##Cnt = 0; \
       for (; *str_##Cnt; str_##Cnt++, ix_##Cnt++) \
         if (ix_##Cnt < sizeof(buf_##Cnt)-1) \
             buf_##Cnt[ix_##Cnt] = toupper(*str_##Cnt); \
       buf_##Cnt; )}
    
  • 自定义 GCC,可能使用 MELT(一种扩展 GCC 的领域特定语言),以提供您的 __builtin_capitalize_constant 来完成这项工作(编辑:MELT 现在是一个非活动项目)。或者用你自己的GCC plugin 编写 C++ 代码(注意,它只适用于一个给定的 GCC 版本)。

【讨论】:

  • 我认为这个答案几乎涵盖了所有的选择。谢谢。
【解决方案2】:

完全使用 c 预处理器是不可能做到这一点的。这样做的原因是预处理器将输入读取为(原子)pp-tokens,它从中组成输出。预处理器没有任何构造可以以任何方式将pp-token 分解为单个字符(无论如何,这里没有人可以帮助您)。

在您的示例中,当预处理器读取字符串文字"flag" 时,预处理器基本上是一个原子文本块。它具有有条件地删除这些块或将它们粘合成更大块的构造。

在某种意义上允许您分解pp-token 的唯一构造是通过一些表达式。然而,这些表达式只能用于算术类型,这就是为什么它们在这里对您没有帮助。

您的方法通过使用 C 语言结构来规避这个问题,即您在运行时进行转换。预处理器唯一要做的就是插入 C 代码来转换字符串。

【讨论】:

    猜你喜欢
    • 2011-08-17
    • 1970-01-01
    • 1970-01-01
    • 2017-02-25
    • 1970-01-01
    • 2011-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多