74

我正在寻找一种将预处理器令牌转换为字符串的方法。

具体来说,我在某个地方得到了:

#define MAX_LEN 16

我想用它来防止缓冲区溢出:

char val[MAX_LEN+1]; // room for \0
sscanf(buf, "%"MAX_LEN"s", val);

我愿意接受其他方式来完成同样的事情,但仅限于标准库。

4

6 回答 6

121

具体见http://www.decompile.com/cpp/faq/file_and_line_error_string.htm

#define STRINGIFY(x) #x
#define TOSTRING(x) STRINGIFY(x)
#define AT __FILE__ ":" TOSTRING(__LINE__)

所以你的问题可以通过做来解决 sscanf(buf, "%" TOSTRING(MAX_LEN) "s", val);

于 2008-10-27T15:47:38.133 回答
24

我在网上找到了答案。

#define VERSION_MAJOR 4
#define VERSION_MINOR 47

#define VERSION_STRING "v" #VERSION_MAJOR "." #VERSION_MINOR

以上不起作用,但希望能说明我想做的事情,即使 VERSION_STRING 最终成为“v4.47”。

要生成正确的数字形式,请使用类似

#define VERSION_MAJOR 4
#define VERSION_MINOR 47

#define STRINGIZE2(s) #s
#define STRINGIZE(s) STRINGIZE2(s)
#define VERSION_STRING "v" STRINGIZE(VERSION_MAJOR) \
"." STRINGIZE(VERSION_MINOR)

#include <stdio.h>
int main() {
    printf ("%s\n", VERSION_STRING);
    return 0;
}
于 2008-10-27T15:45:33.443 回答
7

已经有一段时间了,但这应该有效:

 sscanf(buf, "%" #MAX_LEN "s", val);

如果没有,则需要“双重扩展”技巧:

 #define STR1(x)  #x
 #define STR(x)  STR1(x)
 sscanf(buf, "%" STR(MAX_LEN) "s", val);
于 2008-10-27T15:46:45.703 回答
3

您应该使用双扩展字符串化宏技巧。或者只是有一个

#define MAX_LEN    16
#define MAX_LEN_S "16"

char val[MAX_LEN+1];
sscanf(buf, "%"MAX_LEN_S"s", val);

并保持同步。(这有点麻烦,但只要定义彼此相邻,您可能会记得。)

实际上,在这种特殊情况下,还strncpy不够吗?

strncpy(val, buf, MAX_LEN);
val[MAX_LEN] = '\0';

但是,如果是printf,这将更容易:

sprintf(buf, "%.*s", MAX_LEN, val);
于 2008-10-27T20:32:57.870 回答
1

虽然上述一些“工作”,但我个人建议只使用简单的字符串 API 而不是 libc 中的 deck。有许多可移植的 API,其中一些还为便于包含在您的项目中而进行了优化……而像ustr这样的一些 API具有很小的空间开销并支持堆栈变量。

于 2008-10-28T14:59:16.407 回答
0

我的两分钱。

#define MAX_LEN 16

#define AUX_VALUE(x) x
#define QUOTATION_VALUE() "
#define STRINGIFY(x) #x //Ok in all.
//#define STRINGIFY(x) QUOTATION_VALUE()AUX_VALUE(x)QUOTATION_VALUE() //Ok only in VC++

std::string str = STRINGIFY(MAX_LEN);
const char* str2 = STRINGIFY(MAX_LEN);
sscanf(buf, "%" STRINGIFY(MAX_LEN) "s", val);
于 2020-05-14T20:11:47.807 回答