如何在格式字符串中使用定义?

How to use a define inside a format string?

假设我有一个字符数组:

#define LEN 10
char arr[LEN + 1];

让我们对其进行一些扫描操作:

scanf("Name: %s", arr);

如果有人输入超过 10 个字符的名称,这可能很危险。所以最好使用这个:

scanf("Name: %10s", arr);

好吧,如果 LEN 发生变化,我 运行 会遇到麻烦。我将不得不检查整个代码以更正我在 arr 上下文中使用 10 的每一行。所以我想到了这样的事情:

scanf("Name: %LENs", arr);

但这不起作用。LEN 未被预处理器解析,因为它在字符串中使用。

如何在格式字符串中使用定义?

C 连接相邻的字符串文字,您可以使用 # 对预处理器参数进行字符串化,因此以下应该可以解决问题:

#define LEN 10

// this converts to string
#define STR_(X) #X

// this makes sure the argument is expanded before converting to string
#define STR(X) STR_(X)

[...]

scanf("Name: %" STR(LEN) "s", arr);

宏是必需的,因为只有 #LEN,你最终会得到 LEN 扩展到 10,并且只有一个宏将 # 应用于它的参数,结果将是 "LEN"(参数不会展开)。

预处理器/编译器将按以下步骤对其进行转换:

1. scanf("Name: %" STR_(10) "s", arr);
2. scanf("Name: %" "10" "s", arr);
3. scanf("Name: %10s", arr);

在最后一步中,字符串文字被合并为一个。


附带说明一下,您的 scanf() 格式字符串将要求用户逐字输入

Name: xyz

实际匹配。我怀疑这是你想要的。你可能想要这样的东西:

fputs("Name: ", stdout);
fflush(stdout);
scanf("%" STR(LEN) "s", arr);

也可以考虑完全不使用 scanf()。例如fgets(),这整个预处理器魔术已经过时了。关于不应该使用 scanf() 的原因,请参阅我的 beginners' guide away from scanf().