开发者

What is the minimum buffer size for sprintf with %g?

The problem is to statically allocate a buffer large enough to fit a printed double, formatted with %g at maximum precision. This seems like a simple enough task, bu I'm having trouble. The best I have come up with (assuming the number to be printed is x) is

char buf[1 + DBL_DIG + DBL_DIG + 1 + 1 + 1 + DBL_DIG + 1];
int len = sprintf(buf, "%.*g", DBL_DIG, x);

The DBL_DIG macro is from float.h, and apparently it is supposed to indicate the maximum precision for the type double. We need:

  • 1 byte for a negative sign
  • enough bytes to capture the significant digits
  • at most one 'separator' char (comma, etc.) per digit
  • 1 byte for a decimal point
  • 1 byte for 'e'
  • 1 byte for the sign on the exponent
  • some bytes for the exponent
  • 1 byte for the trailing null written by sprintf.

I'm using the number of sign开发者_开发技巧ificant digits as an upper bound on the number of digits in the exponent. Have I made any errors? Is there a better solution? Should I just allocate 64, 128, or 256 bytes and hope for the best?


You cannot pre-calculate the size at compile time. The %g formatter takes the locale into account (for the 1000's separator etc.) See http://linux.die.net/man/3/sprintf for a description on how to calculate the size safely.


Use snprintf() to find out how many characters you need:

#include <float.h> /* DBL_DIG */
#include <stdio.h>
#include <stdlib.h>

int main(void) {
  double x = rand() / (double)RAND_MAX;
  char find_len[1];
  int need_len;
  char *buf;

  need_len = snprintf(find_len, 1, "%.*g", DBL_DIG, x);
  buf = malloc(need_len + 1);
  if (buf) {
    int used = sprintf(buf, "%.*g", DBL_DIG, x);
    printf("need: %d; buf:[%s]; used:%d\n", need_len, buf, used);
    free(buf);
  }
  return 0;
}

You need a C99 compiler for snprintf().
snprintf() was defined by the C99 standard. A C89 implementation is not required to have snprintf() defined, and if it has as an extension, it is not required to "work" as described by the C99 Standard.


Instead of using sprintf, you could use asprintf. This allocates a buffer of the correct size to fit your string.


Two things: %g does not show all of the representable digits, %g shows a nice-for-humans rounded result. You can specify the precision using %f or %e if you would like a different result.

Never use sprintf() rather than using snprintf(). In your case: int len = snprintf(buf, dimensionof(buf), "%.*f", DBL_DIG, x);


Should I just round up to 64, 128, or 256 and hope for the best?

Yes, just do that -.-

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜