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

eDe*_*ser 12 c format-specifiers c-preprocessor

说我有一个字符数组:

#define LEN 10
char arr[LEN + 1];
Run Code Online (Sandbox Code Playgroud)

让我们做一些scanf操作:

scanf("Name: %s", arr);
Run Code Online (Sandbox Code Playgroud)

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

scanf("Name: %10s", arr);
Run Code Online (Sandbox Code Playgroud)

那么现在如果LEN改变我会遇到麻烦.我将不得不通过整个代码来纠正我10在上下文中使用的每一行arr.所以我想到了这样的事:

scanf("Name: %LENs", arr);
Run Code Online (Sandbox Code Playgroud)

但这不起作用.LEN由于在字符串中使用,因此预处理器无法解析.

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

小智 22

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

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

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

1. scanf("Name: %" STR_(10) "s", arr);
2. scanf("Name: %" "10" "s", arr);
3. scanf("Name: %10s", arr);
Run Code Online (Sandbox Code Playgroud)

在最后一步中,字符串文字连接成一个字符串.


另外,您的scanf()格式字符串将要求用户输入字面

Name: xyz
Run Code Online (Sandbox Code Playgroud)

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

fputs("Name: ", stdout);
fflush(stdout);
scanf("%" STR(LEN) "s", arr);
Run Code Online (Sandbox Code Playgroud)

也考虑不要使用scanf().例如fgets(),这整个预处理器的魔力已经过时了.由于您不应该使用的原因scanf(),请参阅我的初学者指南scanf().

  • 如果有人坚持使用`scanf`,这绝对是正确的答案。明智的做法是在`#define LEN` 之前添加明确的注释,指出它_必须_是一个简单的十进制整数而不是表达式等。 (2认同)