John Millikin
John Millikin

Reputation: 201056

How do I safely format floats/doubles with C's sprintf()?

I'm porting one of my C++ libraries to a somewhat wonky compiler -- it doesn't support stringstreams, or C99 features like snprintf(). I need to format int, float, etc values as char*, and the only options available seem to be 1) use sprintf() 2) hand-roll formatting procedures.

Given this, how do I determine (at either compile- or run-time) how many bytes are required for a formatted floating-point value? My library might be used for fuzz-testing, so it needs to handle even unusual or extreme values.

Alternatively, is there a small (100-200 lines preferred), portable implementation of snprintf() available that I could simply bundle with my library?

Ideally, I would end up with either normal snprintf()-based code, or something like this:

static const size_t FLOAT_BUFFER_SIZE = /* calculate max buffer somehow */;

char *fmt_double(double x)
{
    char *buf = new char[FLOAT_BUFFER_SIZE + 1];
    sprintf(buf, "%f", x);
    return buf;
}

Related questions:

Upvotes: 4

Views: 2121

Answers (2)

please delete me
please delete me

Reputation:

Does the compiler support any of ecvt, fcvt or gcvt? They are a bit freakish, and hard to use, but they have their own buffer (ecvt, fcvt) and/or you may get lucky and find the system headers have, as in VC++, a definition of the maximum number of chars gcvt will produce. And you can take it from there.

Failing that, I'd consider the following quite acceptable, along the lines of the code provided. 500 chars is pretty conservative for a double; valid values are roughly 10^-308 to 10^308, so even if the implementation is determined to be annoying by printing out all the digits there should be no overflow.

char *fmt_double(double d) {
    static char buf[500];
    sprintf(buf,"%f",d);
    assert(buf[sizeof buf-1]==0);//if this fails, increase buffer size!
    return strdup(buf);
}

This doesn't exactly provide any amazing guarantees, but it should be pretty safe(tm). I think that's as good as it gets with this sort of approach, unfortunately. But if you're in the habit of regularly running debug builds, you should at least get early warning of any problems...

Upvotes: 3

user325117
user325117

Reputation:

I think GNU Libiberty is what you want. You can just include the implementation of snprintf.

vasprintf.c - 152 LOC.

Upvotes: 1

Related Questions