忽略有时候有更好的非宏方式(我有充分的理由,遗憾的是),我需要使用宏编写一大堆通用代码。本质上是一个宏库,它将为某些预先指定的类型生成大量函数。
为了避免破坏大量预先存在的单元测试,库必须做的一件事是,对于每种类型,都要在所有大写字母中生成该类型的名称以进行打印。例如。类型“标志”必须打印为“标记”。
我可以手动写出每种类型的常量,例如
#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生成的字符串文字的内容,无论如何,我的循环宏需要一个列表字符指针迭代(即它遍历列表,而不是索引等)。
思想?
答案 0 :(得分:15)
便携式C99中不可能有一个宏将常量字符串转换为全部大写字母(特别是因为字母的概念与字符编码有关.UTF8字母与ASCII字母不同)。
但是,您可以考虑其他一些解决方案。
自定义您的编辑器。例如,您可以编写一些emacs代码,根据需要更新每个C源文件。
在C源代码上使用一些预处理器(可能是一个简单的C代码生成器脚本,它会在某些#define
- d文件中发出一堆#include
。
使用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是现在是不活跃的项目)。或者使用C ++编写自己的GCC plugin代码(警告,它只适用于一个给定的GCC版本)。
答案 1 :(得分:1)
使用c预处理器完全无法完成此操作。原因是预处理器将输入读取为(原子)pp-tokens
,从中组成输出。预处理器没有任何构造可以以任何方式将pp-token
分解为单个字符(无论如何都没有人可以帮助你)。
在您的示例中,当预处理器读取字符串文字"flag"
时,预处理器基本上是一个原子文本块。它有结构有条件地去除这些块或将它们粘合在一起形成更大的块。
允许您在某种意义上分解pp-token
的唯一构造是通过一些表达式。但是这些表达式只适用于算术类型,这就是为什么它们在这里无法帮助你。
您的方法通过使用C语言构造来解决此问题,即您在运行时进行转换。然后预处理器唯一要做的就是插入C代码来转换字符串。