【问题标题】:Buffer size for converting unsigned long to string将 unsigned long 转换为字符串的缓冲区大小
【发布时间】:2015-10-10 17:41:35
【问题描述】:

关于问题和答案 here:我可以使用这种方法,以便解决方案独立于平台。

char *buff = (char*) malloc(sizeof(unsigned long)*8);
sprintf(buff, "%lu", unsigned_long_variable);

在这里我得到缓冲区长度的值,因为它类似于 unsigned long 变量。这种方法正确吗?

【问题讨论】:

  • see why not to castmalloc()C中的family返回值。
  • @SouravGhosh :感谢您的提示,但这与我的疑问有关吗?!我试图了解上述方法是否独立于平台。我想了解上述方法是否正确。如有不妥,纯属理解学习之用!!
  • @SouravGhosh,这是你的习惯吗?到处张贴这个无关紧要且备受争议的建议?
  • @SouravGhosh:问题是也有参数 for 转换返回值(请参阅 unwind 接受的答案下的 cmets),并在每个问题下发布该链接确实演员malloc() 是......好吧,如果我在每个违反它的问题下发布指向我最喜欢的编码风格指南的链接,你会说什么?
  • @DevSolar 先生,也许对于像我们这样的“常客”来说,这是重复的,但我认为这对于通过谷歌搜索登陆特定问题的人很有用。另外,我从未说过这是必须。我添加了指向问题本身的链接(以避免任何可能的偏见),其中最受好评的答案有利于评论正文。 :-)

标签: c string pointers malloc


【解决方案1】:

甚至不要尝试来计算缓冲区大小。

snprintf 开头,它将安全地告诉您需要多少个字符。然后你知道要分配多少字节来安全打印。

由于这是几行代码,您不想一次又一次地重复,请编写一个函数 malloc_printf 来执行您想要的操作:在该函数中,使用 NULL 目标调用 snprintf,然后malloc 缓冲区,sprintf 进入 malloc 缓冲区,然后返回。为了使其更快并经常避免两次 snprintfsprintf 调用,首先写入 256 个字符的缓冲区,这通常就足够了。

所以你的最终代码是

char* buff = malloc_printf ("%lu", unsigned_long_variable);

还可以使用%s%s 格式进行快速、安全和简单的字符串连接,例如。

【讨论】:

  • 感谢您的建议。事实上,我也在我的代码中使用了它。但其他答案消除了我的疑问。谢谢顺便说一句。
【解决方案2】:

您想知道需要多少个字符才能表示最大可能的unsigned long。对吗?

为此,您正在尝试计算最大可能的unsigned long

sizeof(unsigned long)*8

这在几个方面是错误的。其一,sizeof 返回 char 的倍数,不必是 8 位。你应该乘以CHAR_BIT(来自<limits.h>)。但即使这样也没有必要,因为同样的标头已经提供了最大可能的值——UCHAR_MAX

那么你犯了一个错误:你的计算给出了unsigned long整数表示的大小。你想要字符字符串表示的大小。这可以通过log10() 函数(来自<math.h>)来实现:

log10( UCHAR_MAX )

这将为您提供一个double 值,该值指示UCHAR_MAX 中的(十进制)位数。这将是一个分数,您需要将其四舍五入 (1)(ceil() 会为您执行此操作)。

因此:

#include <math.h>
#include <stdlib.h>
#include <limits.h>

int main()
{
    char * buff = malloc( ceil( log10( UCHAR_MAX ) ) + 1 );
    //...
}

总而言之,这很狡猾(我在写这篇文章时犯了两个错误,真丢脸——如果你在使用它时犯了错误,真丢脸)。它需要使用数学库来完成 snprintf( NULL, ... ) 可以更轻松地为您做的事情,正如您链接到的问答所示。


(1):log10( 9999 ) 位数字提供 3.9999565...

【讨论】:

  • 但与解释相反,您的代码进行了汇总。或者,您忘记了尾随的 0。此外,C 的 log 是自然对数。我们需要 `log10' 。
  • 一般建议:只要您的源代码中出现的数字不是10,那就是代码异味,也就是unnamed numerical constant。这表明你做错了什么。
  • @undur_gongor:哎呀......“发布前测试”的另一个教训。我打算用+ 1 进行汇总,并立即忘记了空字节终止符。 :-D
  • 我看到很多代码包含 #define TWO 2 之类的内容,这是由于错误应用该建议而导致的。
  • @undur_gongor:我什至见过#define TWO 3一次。不开玩笑。但是,如果您下定决心,您可能会误用 任何 建议。我说的是“代码异味”,意思是你可能做错了什么,而不是你正在做错什么。 (例如,您需要2 来检查偶数。)
【解决方案3】:

The C standard doesn't put an upper limit to the number of bits per char.

如果有人构建了一个 C 编译器,例如每个字符使用 2000 位,则输出可能会溢出缓冲区。

您应该使用来自limits.h 的CHAR_BIT 而不是8

另外,请注意,每 3 位需要(略少于)1 个字符,并且字符串终止符需要 1 个字节。

所以,是这样的:

#include <limit.h>

char *buff = malloc(1 + (sizeof(unsigned long) * CHAR_BIT + 2) / 3);
sprintf(buff, "%lu", unsigned_long_variable);

【讨论】:

    【解决方案4】:

    不,这不是计算缓冲区大小的正确方法。

    例如对于 4 字节无符号长整数,您的值最高为 2^32-1 这意味着 10 位十进制数字。所以你的缓冲区需要 11 个字符。

    您分配的是 4 * 8 = 32。

    正确的公式是

    ceil(log10(2^(sizeof(unsigned long) * CHAR_BIT) - 1)) + 1
    

    log10这里表示十进制对数)

    一个好的(安全的)估计是:

    (sizeof(unsigned long) * CHAR_BIT + 2) / 3 + 1
    

    因为 log10(2) 小于 0.33。

    【讨论】:

    • 使用CHAR_BIT 消除关于字符大小的假设
    【解决方案5】:

    简答:

    #define INTEGER_STRING_SIZE(t) (sizeof (t) * CHAR_BIT / 3 + 3)
    
    unsigned long x;
    char buf[INTEGER_STRING_SIZE(x)];
    int len = snprintf(buf, sizeof buf, "%lu", x);
    if (len < 0 || len >= sizeof buf) Handle_UnexpectedOutput();
    

    OP 对sizeof(unsigned long)*8 的使用很弱。在CHAR_BIT(每个char 的位数)很大(必须至少为8)的系统上,sizeof(unsigned long) 可能是1。1*8char 对于4294967295ULONG_MAX 的最小值)。

    关于:sprintf()/snprintf() 鉴于 locale 问题,理论上,代码可能会打印额外的字符,例如 4,294,967,295,因此会超出预期的缓冲区。除非出现非常严格的内存限制,否则建议使用 2 倍预期大小的缓冲区。

    char buf[ULONG_STRING_SIZE * 2];  // 2x
    int len = snprintf(buf, sizeof buf, "%lu", x);
    

    打印一些无符号整数的预期最大字符串宽度是ceil(log10(unsigned_MAX)) + 1。在unsigned long的情况下,ULONG_MAX的值肯定不会超过pow(2,sizeof (unsigned long) * CHAR_BIT) - 1所以代码可以使用:

    #define LOG10_2 0.30102999566398119521373889472449
    #define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * LOG10_2 + 2)
    // For greater portability, should use integer math.
    #define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT / 3 + 2)
    // or more precisely
    #define ULONG_STRING_SIZE (sizeof (unsigned long) * CHAR_BIT * 28/93 + 2)
    

    如果指定了有符号`整数,则使用+3 的简短回答。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-09-23
      相关资源
      最近更新 更多