【问题标题】:Convert a preprocessor token to a string将预处理器标记转换为字符串
【发布时间】:2010-09-19 09:56:48
【问题描述】:

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

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

#define MAX_LEN 16

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

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

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

【问题讨论】:

标签: c c-preprocessor stringification


【解决方案1】:

我在网上找到了答案。

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

【讨论】:

    【解决方案2】:

    已经有一段时间了,但这应该可以工作:

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

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

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

    【讨论】:

    • 第一个不行; # 对宏扩展中的宏参数进行字符串化。第二个会起作用。
    • @RaviRaj — 因为# 只对宏参数进行字符串化,并且第一行不在宏体中。
    【解决方案3】:

    见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 我希望我能给你这个评论的代表! :)
    【解决方案4】:

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

    #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 不会在超出缓冲区时终止字符串,如果字符串太短则写入额外数据。
    【解决方案5】:

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

    【讨论】:

      【解决方案6】:

      我的两分钱。

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

      【讨论】:

        猜你喜欢
        • 2013-05-11
        • 1970-01-01
        • 2013-03-17
        • 1970-01-01
        • 1970-01-01
        • 2011-08-17
        • 2022-01-19
        • 1970-01-01
        相关资源
        最近更新 更多