有没有像g_printf_string_upper_bound这样的可移植函数?

时间:2015-03-31 13:18:27

标签: c string printf

为了生成文件名,我需要为sprintf提供一些缓冲区内存。这些缓冲区的大小在过去是相当随意选择的。这可能很容易导致将来非常讨厌的堆栈溢出错误,例如, int长度为64位,但字符串缓冲区大小仅为10个字符,因为这是32位int可容纳的最大位数。

一些MWE:

  for (int i = 0; i < mpi_size; i++) {
     //magic number: 32bit integer has 10 digits, 
     //+6 for "/rank_", +1 for null termination
     char path2[strlen(path) + 17];
     //This can possibly be an access violation, or a very hard to
     //find bug:
     sprintf(path2, "%s/rank_%d", path, i);
     //Using path2 to access some file
  }

在其他地方选择完全不同的尺码,人们非常肯定,int不会大于例如3位数。这可能会使问题变得更加容易。

什么是完美便携的解决方案?

我在gnome库中找到了函数g_printf_string_upper_bound,可以优雅可靠地解决这个问题。

在C标准,POSIX或其他地方有这样的东西吗?

3 个答案:

答案 0 :(得分:3)

虽然被广泛误解,snprintf专门用于解决此类情况。

snprintf的返回值是 写入的长度(不包括尾随的NUL),如果缓冲区足够大以容纳它。因此,您可以分两步使用它:使用空缓冲区调用一次以找到所需的长度,使用它来分配必要的空间,然后再次调用它以产生结果:

size_t length = snprintf(NULL, 0, "%s/rank_%d", path, i) + 1;

char path2[length];

snprintf(path2, length, "%s/rank_%d", path, i);

<子> 至于这是使用snprintf的预期方式,是的,我很确定它确实存在。我将这一陈述建立在与Peter Seebach谈话的基础上,Peter Seebach表示,当他加入C标准委员会时,他的主要目的是让snprintf进入标准。

<子> 就此而言,我可能不得不对这种方法承担一点责任,我承认这是一种污点。在snprintf被发明之前回来,我写了a post on comp.lang.c.moderated,显示即使没有snprintf,如何做同样的事情。为此,它打开了一个临时文件并将输出写入它以获取返回值,然后使用malloc分配缓冲区,最后使用sprintf将数据放入缓冲区。

<子> snprintf使用相同的基本思想,但无需打开外部文件即可使用它。尽管如此,它仍然使用了我发布的技术,据我所知,我是第一个提出这种一般方法的人(虽然我可以很容易地相信其他人可能首先想到它,但是发帖太惭愧了它)。

答案 1 :(得分:2)

考虑asprintf()。它将根据需要分配需求空间。唯一预期的失败是内存耗尽。它不是标准的C函数,但可以在许多* nix系统上使用。否则:

建议2个步骤:

  1. 根据参数将缓冲区缩放到输出的预期最大大小。如果几个字节太大就应该没问题。

    // e.g. size needed to print INT_MIN
    #define INT_SIZE_MAX (sizeof(int)*CHAR_BIT/3 + 3)
    
    const char rank[] = "/rank_";
    char path2[strlen(path) + sizeof rank + INT_SIZE_MAX + 1];
    sprintf(path2, "%s%s%d", path, rank, i);
    
  2. 确保snprinf()

    没有溢出
    int n = snprintf(path2, sizeof path2, "%s%s%d", path, rank, i);
    if (n >= sizeof path2 || n < 0) HandleRareFailure();
    

  3. snprintf()可能失败的原因:
    1)某些字节序列无效(编码错误) 2)区域设置更改导致逗号添加到%d - &gt; &#34; 1234567890&#34 ;.
    3)月相。见下面的评论。

答案 2 :(得分:-6)

  

C标准中有这样的东西,[或]在POSIX中吗?

  

或其他地方?

Gnome图书馆里有类似的东西......:P