使用snprintf()有效确定字符数组大小

时间:2015-09-06 05:56:55

标签: c

我们有一份来自大学的小作业,要求我们在C中完成一些工作。 该问题的一部分是将无符号长号转换为字符串,该无符号长号在程序过程中生成,因此无需预先确定它。当然,我使用了snprintf。我初始化了一个数组(str [50]),其大小足以避免任何类型的缓冲区错误。

然而,在提交时,我的教授说我的避免缓冲错误的方法是无效的。

我现在的问题是,当我创建一个char数组来保存unsigned long值时,我将它作为什么尺寸?是否有一些C宏来帮助确定无符号长整数可以容纳的最大字符数?

可能有点像,

char str[MAX_NUMBER_OF_DIGITS_OF_UNSIGNED_LONG_ON_MACHINE];

我已经浏览过limit.h和一些博客和这个论坛,但没有任何协议。任何帮助将不胜感激!

3 个答案:

答案 0 :(得分:1)

来自snprintf的文件:

  

关于snprintf(),SUSv2和C99的返回值   顶撞          彼此:当使用size = 0调用snprintf()时,SUSv2规定          未指定的返回值小于1,而C99允许str为          在这种情况下为NULL,并给出返回值(一如既往)作为数字          在输出字符串的情况下写入的字符数          已经够大了。

如果您使用的是C99,可以使用snprintf确定尺寸(如BLUEPIXY所评论):

int size = snprintf(NULL, 0, "%lu", ULONG_MAX);

但是,如果您不能使用C99,则可以通过确定所需的位数并为终止\0字符添加其他字符来确定字符串大小:

int size = (int) log10((double) ULONG_MAX) + 1;

为了使用size字节分配数组,您只需使用

即可
char str[size];

然而,只有当您的编译器/版本支持VLAs时,这才有效,如果编译器不支持此功能,您可以使用

动态分配数组
char *str = malloc(size);    //< Allocate the memory dynamically
// TODO: Use the str as you would the character array
free(str);                   //< Free the array when you are finished

答案 1 :(得分:1)

#if ULONG_MAX == 4294967295UL
#  define SIZE (10 + 1)
#elif ULONG_MAX <= 18446744073709551615ULL
#  define SIZE (20 + 1)
#endif

答案 2 :(得分:1)

为了简洁,请使用@BLUEPIXY

更深层次的回答。

C允许各种“语言环境”,理论上,snprintf(..., "%lu",...)可以打印比预期更长的字符串。而不是“1234567”,输出可能是“1,234,567”。

推荐:
1.确定最大整数的位大小n 2. n * log2(10)四舍五入+ 1然后计算char 3.设置最大需要2倍的缓冲区 4.检查snprintf结果。
5.关键问题:使用snprintf()的双重呼叫需要确保“语言环境”和号码不会在呼叫之间发生变化 - 这里不使用snprintf()这是一个功能上很昂贵的呼叫。

char *ulong_to_buf(char *buf, size_t size, unsigned long x) {
    int n = snprintf(buf, size, "%lu", x);
    if (n < 0 || n >= size) return NULL;
    return buf;
}

// Usage example
void foo(unsigned long x)
  // 1/3 --> ~log2(10)
  #define ULONG_PRT_LEN (sizeof(unsigned long)*CHAR_BIT/3 + 2)
  char buf[ULONG_PRT_LEN*2 + 1];  // 2x for unexpected locales
  if (ulong_to_buf(, sizeof buf, x)) {
    puts(buf);
  }

如果代码真的,那么简单编写自己的

#include <stdlib.h>
#include <limits.h>
#include <string.h>
#define PRT_ULONG_SIZE (sizeof(unsigned long) * CHAR_BIT * 10 / 33 + 3)

char *ulong_strnull(int x, char *dest, size_t dest_size) {
  char buf[PRT_ULONG_SIZE];
  char *p = &buf[sizeof buf - 1];
  // Form string
  *p = '\0';
  do {
    *--p = x % 10 + '0';
    x /= 10;
  } while (x);
  size_t src_size = &buf[sizeof buf] - p;
  if (src_size > dest_size) {
    // Not enough room
    return NULL;
  }
  return memcpy(dest, p, src_size); // Copy string
}