C宏对变量进行字符串化

时间:2019-01-31 11:07:05

标签: c string macros

何时可以将变量的值传递给宏以进行分类?

例如,从this post提取的代码可与常量定义的宏一起使用。

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

{
  ...
  char word[MAX_STRING_LENGTH+1];     
  scanf("%" STRINGIFY(MAX_STRING_LENGTH) "s", word);
  ...
}

但是我不能将其与诸如以下变量一起使用:

{
  ...
  int val = 20;
  char word[MAX_STRING_LENGTH+1];     
  scanf("%" STRINGIFY(val) "s", word);
  ...
}

由于编译成功并显示以下警告:

warning: invalid conversion specifier 'v' [-Wformat-invalid-specifier]
    scanf("%" STRINGIFY(var) "s", word);
           ~~~^~~~~~~~~~~~~
test2.c:4:22: note: expanded from macro 'STRINGIFY'
#define STRINGIFY(x) STRINGIFY2(x)
                     ^
test2.c:5:23: note: expanded from macro 'STRINGIFY2'
#define STRINGIFY2(x) #x
                      ^
<scratch space>:466:2: note: expanded from here
"var"
 ^
1 warning generated

但是代码运行不会等待任何输入。

相反,在this other post中,可以将变量传递给该宏:

#define PRINT(int) printf(#int "%d\n",int)
...
int var =8;
PRINT(var);

这两种情况有什么区别?如何修改第一个,使其也接受变量?

我尝试在宏中使用%d,但未成功。

2 个答案:

答案 0 :(得分:3)

STRINGIFY(val)将产生"val",而不是您要字符串化的值,因此您得到的最终格式字符串为"%vals""%" "val" "s")。这就是C预处理器的工作方式,它只执行文本替换,仅此而已。

PRINT示例:

#define PRINT(int) printf(#int "%d\n", int)

PRINT(var);                // to be resolved
printf(#var  "%d\n", var); // intermediate result
printf("var" "%d\n", var); // final result, this is what the C compiler sees

但是为什么它可以与MAX_STRING_LENGTH一起使用?

#define MAX_STRING_LENGTH 20
#define STRINGIFY(x) STRINGIFY2(x)
#define STRINGIFY2(x) #x

STRINGIFY(MAX_STRING_LENGTH)  // to be resolved
STRINGIFY2(20)                // intermediate step; STRINGIFY2 known as macro, thus:
#20                           // another intermediate step
"20"                          // final result

答案 1 :(得分:3)

预处理器始终仅对令牌运行。

宏不是函数。您不向其传递变量(按值)。您传递令牌序列。在STRINGIFY(MAX_STRING_LENGTH)中,令牌序列为MAX_STRING_LENGTH,在STRINGIFY(val)中,令牌序列为val

MAX_STRING_LENGTH本身是一个宏,由于STRINGIFY的定义工作方式,该宏将在被转换为字符串文字之前由预处理器进行扩展。因此,20就是应用了#的令牌,并产生"20"作为字符串文字。

另一方面,val不是宏,preprcosseor不会扩展它。它将令牌序列保持为valval是具有某些值的变量的名称,对预处理器来说没什么,它只关心令牌。因此val转换为文字"val"

您从另一篇文章中摘录的示例之所以有用,是因为它扩展到了这一点:

printf("var" "%d\n", var);

#int中的变量名称变成了文字,没有任何魔术可以使预处理器读取变量的值。打印var 8的事实仅仅是因为将var作为参数传递给printf%d说明符在运行时打印。

最后,当尝试使用preprcoessor时,在完成prpeprocessing之后但在编译文件之前查看源文件总是有帮助的。 gcc -E标志(或与您的编译器等效的标志)可以帮助您实现这一目标。