C 宏将变量字符串化

Fra*_*Boi 1 c string macros

什么时候可以将变量的值传递给宏进行字符串化?

例如,本文中的代码适用于常量定义的宏。

#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);
  ...
}
Run Code Online (Sandbox Code Playgroud)

但是我不能将它与变量一起使用,例如:

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

因为编译成功并出现此警告:

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
Run Code Online (Sandbox Code Playgroud)

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

相反,在另一篇文章中,可以将变量传递给该宏:

#define PRINT(int) printf(#int "%d\n",int)
...
int var =8;
PRINT(var);
Run Code Online (Sandbox Code Playgroud)

这两种情况有什么区别?如何修改第一个以便它也接受变量?

我尝试%d在宏内部使用,但没有成功。

Sto*_*ica 5

预处理器始终仅对令牌进行操作。

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

MAX_STRING_LENGTH本身是一个宏,并且由于STRINGIFY定义的工作方式,宏将在将其转换为字符串文字之前由预处理器扩展。20依次应用到它的标记也是如此#,并且它生"20"成为字符串文字。

另一方面,val它不是宏,预处理器不会扩展它。它将保持令牌序列为val。事实上val,具有某个值的变量名称对预处理器来说没有任何意义,它只关心标记。所以val就转化为字面意思了"val"

您从另一篇文章中带来的示例有效,因为它扩展为:

printf("var" "%d\n", var);
Run Code Online (Sandbox Code Playgroud)

变量名#int变成了文字,没有什么魔法可以让预处理器读取变量的值。事实var 8被打印只是因为var作为参数传递给printf! 它由%d说明符在运行时打印。

最后,在尝试预处理器时,在 prpeprocessing 完成之后、编译文件之前查看源文件总是有帮助的。该gcc -E标志(或编译器的等效标志)可以帮助您做到这一点。

  • @StoryTeller 但这仅适用于 printf,scanf 不支持此(不幸的是!)... (2认同)