【问题标题】:How to determine the size of the char array really need?如何确定真正需要的char数组的大小?
【发布时间】:2014-10-22 14:19:18
【问题描述】:

我对以下代码有疑问:

void testing(int idNumber)
{
    char name[20];

    snprintf(name, sizeof(name), "number_%d", idNumber);
}

char数组name的大小是20,所以如果idNumber111就可以了,但是实际idNumber是111111111111111111111111111111怎么样,怎么判断char数组应该有多大为了保留snprintf的结果?

【问题讨论】:

  • 计算任何数字类型所需的大小很容易:2^(sizeof(type) * 8) 是该类型的最大(无符号)值。单字节类型(charshort)允许 3 位数字、2 字节 5(int 的最小大小)、8、10、13 等(因此间隔为 2 或3 个字符)。为终止\0 字符添加符号字符和空间,sizeof(type) * 3 + 2 应该可以解决问题。如果您正在处理 doubles 和 floats,请添加小数点空间
  • @Elias Van Ootegem 注意:处理 double"%f" 可能需要一个大小为 1 + DBL_MAX_10_EXP + 1 + 1 + 6 +1 的缓冲区用于符号、DBL_MAX 数字、.、分数和 @ 987654339@。在我的平台上至少有 47 个,也许是 318 个char。您建议的公式适用于整数。
  • @chux: 确实...我想看看long double 实现为四精度类型(128 位)的系统所需的长度
  • @Elias Van Ootegem long double 使用一个 B.A.Buffer。 ;-)(可能是 4942 char

标签: c arrays printf


【解决方案1】:

好吧,如果 int 在您的平台上是 32 位,那么它可以打印的最宽值将是 -20 亿,即 11 个字符,因此您需要 7 表示 number_,11 表示 %d , 1 代表空终止符,所以总共 19 个。

但是您通常应该检查来自snprintf() 的返回值,以确保您有足够的空间。例如,如果“locale”设置为不同于标准的“C”之一,它可能会打印千位分隔符,在这种情况下,您需要多 2 个字符。

【讨论】:

    【解决方案2】:

    只有一个好的答案:
    询问snprintf 本身(传递长度为0)。

    如果缓冲区足够大,它会返回输出的大小,不包括终止的 0。

    man-page for snprintf

    标准引用(C99+修正案):

    7.21.6.5 snprintf 函数

    简介

    #include <stdio.h>
    int snprintf(char * restrict s, size_t n,
    const char * restrict format, ...);
    

    说明
    2 snprintf函数等价于fprintf,只是输出写入到 一个数组(由参数s 指定)而不是流。如果n 为零,则不写入任何内容, 而s 可能是一个空指针。否则,n-1st 之外的输出字符为 丢弃而不是写入数组,最后写入一个空字符 实际写入数组的字符数。如果复制发生在对象之间 重叠,行为未定义。
    退货
    3 snprintf 函数返回本应写入的字符数 n 是否足够大,不包括终止的空字符或负数 发生编码错误时的值。因此,空终止输出已 当且仅当返回值为非负且小于n 时才完全写入。

    【讨论】:

    • 类似char name[snprintf(name, 0, "number_%d", idNumber) + 1]; snprintf(name, sizeof(name), "number_%d", idNumber);?
    • 甚至snprintf(NULL, 0, "format", extra, arguments)
    【解决方案3】:

    查看 snprintf 的文档。如果您为目标传递 NULL 并为大小传递 0,它将返回所需的字节数。因此,您首先执行此操作,分配内存,然后执行另一个具有正确大小的 snprintf。

    所有 printf 函数都返回打印的字节数(不包括尾随零),除了 snprintf 将返回如果长度不受限制,打印的字符数。

    【讨论】:

      【解决方案4】:

      引用here:

      如果结果字符串长于 n-1 个字符,则 剩余的字符将被丢弃且不存储,但会被计入 函数返回的值。

      【讨论】:

        【解决方案5】:

        要使用大小合适的缓冲区,请计算其最大需求。

        #define INT_PRINT_SIZE(i) ((sizeof(i) * CHAR_BIT)/3 + 3)
        
        void testing(int idNumber) {
          const char format[] = "number_%d";
          char name[sizeof format + INT_PRINT_SIZE(idNumber)];
          snprintf(name, sizeof(name), format, idNumber);
        }
        

        此方法假定 C 语言环境。更强大的解决方案可以使用

          ...
          int cnt = snprintf(name, sizeof(name), format, idNumber);
          if (cnt < 0 || cnt >= sizeof(name)) Handle_EncodingError_SurprisingLocale().
        

        类似于https://stackoverflow.com/a/26497268/2410359

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-11-24
          • 2014-03-22
          • 1970-01-01
          • 2021-06-07
          • 1970-01-01
          • 2013-07-01
          相关资源
          最近更新 更多