代码之家  ›  专栏  ›  技术社区  ›  OregonTrail

安全地将int转换为C中的字符串

  •  2
  • OregonTrail  · 技术社区  · 10 年前

    根据 top answer on SO 这是我应该做的,将整数转换为C中的字符串:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <inttypes.h>
    #include <math.h>
    
    #define digits(x) ((int)((ceil(log10(abs(x)))+1)*sizeof(char)))
    
    int main () {
        int a = 345908220;
        long b = 23094809284358;
        unsigned int c = 3456789234;
        uint8_t d = 242;
        int64_t e = -840958202029834;
    
        int dstr_len = digits(a) + digits(b) + digits(c) +
                       digits(d) + digits(e) + 5;
    
        char dstr[dstr_len];
        sprintf(dstr, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
    
        printf("%s\n", dstr);
    
        return 0;
    }
    

    然而,这似乎效率低得离谱。我必须将我的程序链接到libmath 数学调用我要打印的每个整数。还要注意,我必须添加 5 到我的缓冲区,而不仅仅是 1 对于 NUL 终止符,通过计算格式字符串中的空格数。这似乎也容易出错,并可能导致缓冲区溢出。

    那么,有什么好的标准函数可以为我计算缓冲区的大小吗?

    我正在尝试编写安全的C。

    4 回复  |  直到 8 年前
        1
  •  5
  •   Remy Lebeau    10 年前

    如果编译器具有 snprintf() 可用时,您可以请求格式化的缓冲区长度,然后相应地分配:

    int dstr_len = snprintf(NULL, 0, "%d %ld %u %u %" PRIu64, a, b, c, d, e) + 1;
    
    char dstr[dstr_len];
    //
    // NOTE: variable-length arrays are NOT supported in all compilers!
    // A more portable solution is:
    //
    // char *dstr = malloc(sizeof(char) * dstr_len);
    
    snprintf(dstr, dstr_len, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
    
    // free(dstr);
    
        2
  •  2
  •   dohashi    10 年前

    您可以为此使用snprintf。从手册页:

    函数snprintf()和vsnprintf()写入的字节数不超过大小(包括指定的空字节(“\0”))。如果输出由于此限制而被截断,则返回 value是本应为 如果有足够的空间可用,则写入最终字符串。因此,大小的返回值 或更多意味着输出被截断。

    因此,您可以使用0作为大小调用它,并捕获返回值,然后根据该值进行分配。

        3
  •  1
  •   OregonTrail    10 年前

    您可以使用 asprintf ,为您分配足够大的输出字符串。

    别忘了 自由的 输出字符串,因为它是动态分配的。

    阿斯普林夫 在Mac OSX、Linux和BSD上可用。这个 source code 如果您希望在其他平台上使用,可以从Apple获得。

    例子:

    #include <stdio.h>
    #include <stdlib.h>
    #include <stdint.h>
    #include <inttypes.h>
    
    int main () {
        int a = 345908220;
        long b = 23094809284358;
        unsigned int c = 3456789234;
        uint8_t d = 242;
        int64_t e = -840958202029834;
    
        char *dstr;
        asprintf(&dstr, "%d %ld %u %u %" PRIu64, a, b, c, d, e);
        if (dstr == NULL) {perror(NULL), exit(1);}
    
        printf("%s\n", dstr);
        free(dstr);
    
        return 0;
    }
    
        4
  •  0
  •   Basile Starynkevitch    10 年前

    大多数C“运行时环境”最多为64位。你可以测试一下 int 最多64位(带 <stdint.h> <limits.h> )然后使用 snprintf (不是 sprintf 这是不安全的,不推荐使用)在足够大的缓冲区(32字节对于2 64 十进制)。

    参见Posix规范 limits.h 定义 WORD_BIT 所以

    #if WORD_BIT > 64
    #error cannot compile on this machine
    #endif
    
    char buf[32];
    snprintf(buf, sizeof(buf), "%d", a);
    

    顺便提一下 <标准时间> 定义 several types 。你可能想要 intmax_t