ChatGPT解决这个技术问题 Extra ChatGPT

将预处理器标记转换为字符串

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

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

#define MAX_LEN 16

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

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

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


p
pfnuesel

具体参见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); 来解决


为什么级联2个宏?一个 TOSTRING 还不够吗?
请参阅下面有关双扩展字符串化的答案。 C/C++ 预处理器又脏又丑,我相信没有标准。所以为什么它需要两个而不是一个我不能说,因为我不想做研究。
@Daniel Brunner 单个宏将粘贴令牌本身,产生字面上 "%" "MAX_LEN" "%" 第二个宏导致令牌 value 被粘贴,例如 "16" 因为 TOSTRING 宏制作最终代码相当于 STRINGIFY(16)
@TimSylvester 我希望我能给你这个评论的代表! :)
d
davenpcj

我在网上找到了答案。

#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 int main() { printf ("%s\n", VERSION_STRING);返回0; }


J
James Curran

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

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

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

 #define STR1(x)  #x
 #define STR(x)  STR1(x)
 sscanf(buf, "%" STR(MAX_LEN) "s", val);

第一个不起作用; # 对宏扩展中的宏参数进行字符串化。第二个将起作用。
@RaviRaj - 因为 # 只对宏参数进行字符串化,并且第一行不在宏的主体中。
A
Artefact2

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

#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);

是的,我希望 * 或其他符号可用于带有参数的长度限制 scanf 例程。这种形式的 sprintf 比 strncpy、imo 工作得更好,因为如果 strncpy 超出缓冲区,它不会终止字符串,如果字符串太短,它会写入额外的数据。
J
James Antill

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


J
Joma

我的两分钱。在我的示例中,要生成的格式是 %16s%16s%d

#include <iostream>

#define MAX_LEN 16

#define AUX(x) #x
#define STRINGIFY(x) AUX(x)

int main() {
    char buffer[] = "Hello World 25";
    char val[MAX_LEN+1]; 
    char val2[MAX_LEN+1];
    int val3;

    char format[] = "%" STRINGIFY(MAX_LEN) "s" "%" STRINGIFY(MAX_LEN) "s" "%d";
    int result = sscanf(buffer, format, val, val2, &val3);
    std::cout<< val << std::endl;
    std::cout<< val2 << std::endl;
    std::cout<< val3 << std::endl;
    std::cout<<"Filled: " << result << " variables" << std::endl;
    std::cout << "Format: " << format << std::endl;
}

https://i.stack.imgur.com/ETlfv.png