C(预处理器):如何 concatenate/append 替换字符串

C (Preprocessor): How to concatenate/append substitution string

我在命令行上定义我的异常:

-DEXCEPTION_1=\"first\" -DEXCEPTION_2=\"second\" -DEXCEPTION_3=\"third\"

我检查了一个字符串:

except = 0;
#ifdef EXCEPTION_1
if (! strcmp(EXCEPTION_1, mystring))
{  except = 1;
}
#endif
#ifdef EXCEPTION_2
if (! strcmp(EXCEPTION_2, mystring))
{  except = 1;
}
#endif
#ifdef EXCEPTION_3
if (! strcmp(EXCEPTION_3, mystring))
{  except = 1;
}
#endif
if (except == 1)
{  // do something
}
else
{  // do something else
}

不用说,虽然这可行,但它也非常丑陋、不灵活并且导致我的代码冗余。

有没有办法将字符串附加到预处理器宏变量?

我想得到这样的东西(问题当然是#append不存在):

#ifdef EXCEPTION_1 #append EXCEPTIONS if (! strcmp(EXCEPTION_1, mystring)) {  except = 1; }
#ifdef EXCEPTION_2 #append EXCEPTIONS if (! strcmp(EXCEPTION_2, mystring)) {  except = 1; }
#ifdef EXCEPTION_3 #append EXCEPTIONS if (! strcmp(EXCEPTION_3, mystring)) {  except = 1; }

然后我可以在代码中使用 EXCEPTIONS,它可以处理所有可能的异常排列。

换句话说,我想将一个字符串附加到一个宏变量 - 这可能吗?

你可以有定义链,但它看起来不会好多少:

#ifdef EXCEPTION_1 
#define EXCEPTIONS1 if (! strcmp(EXCEPTION_1, mystring)) {  except = 1; }
#else
#define EXCEPTIONS1
#endif

#ifdef EXCEPTION_2
#define EXCEPTIONS2 EXCEPTIONS1 if (! strcmp(EXCEPTION_2, mystring)) {  except = 1; }
#else
#define EXCEPTIONS2 EXCEPTIONS1 
#endif

// etc

同样,也好不了多少。

而且您真的 不应该用开放的 if 定义宏。它允许像 if(cond) EXCEPTIONS1 else cout<<"error"; 这样奇怪的交互——这不会像你期望的那样,因为 EXCEPTIONS1 是一个普通的 if 并且会吞噬 else 分支。

用代码块编写宏的典型方法是将整个内容包装在 do{...}while(0) 中(注意没有结尾 ;)。

您可以将宏参数转换为字符串:

#define STR(x)    #x

STR(hello)  -->  "hello"

您可以连接 字符串文字 ,只需将它们并排书写即可:

"123" "abc"  -->  "123abc"

或者创建一个宏:

#define CONCAT(a, b) a b

CONCAT("hello", " world!")  --> "hello world!"

您可以使用 ## 将字符串连接到宏。使用索引并仅使用条件来设置索引。然后最后您可以将索引与您的宏 EXCEPTION 连接起来。像,

定义一个像#define append(name) name ## counter

这样的宏

如果 counter 是 1

,这将反过来给你 name 作为 name1

现在您可以定义不同的 append 宏来将结果放在一个变量中 name

查看标记字符串化和连接部分 here 它可能会帮助一些人。通常,使用命令行宏来填充 table 并拥有一个简单扩展为循环的宏似乎更容易,该循环检查 table 的连续条目以设置例外标志。

例如,将下面的内容保存为silly.c,然后用cc -DEX1=\"hello\"

编译
#include <stdlib.h>
#include <stdio.h>
#include <string.h>

struct Except {
   const char* key;
   int flag;
};

struct Except table[] = {
#if defined(EX1)
   {EX1,1},
#endif
   {NULL,0}
};

#define CHECKEX(mys,rv)  { rv = 0;for(int i=0;table[i].key!=0;i++)      \
         if (strcmp(table[i].key,(mys))==0) \
            rv = 1; \
   }

int main()
{
   int rv;
   CHECKEX("hello",rv);
   if (rv)
      printf("Got an hello\n");
   else printf("Got nothing\n");
   return 0;
}

只需根据需要向 table 添加更多 "blocks"。当然只是建议。