C
Charlie Gordon
Michael Mair said:Keith said:Charlie Gordon said:[...]
No point in calling snprintf again, sprintf would do just fine:
result = sprintf(mem, fmt, arg1, arg2);
And, unless you're really paranoid, you don't even need its return value,
because it *must* be equal to ``needed'' (if the original snprintf call
succeeded, a sprintf call with the same arguments and in the same locale
must return the same value).
Bad advice : if the code for assessing the length is duplicated for
the actual formatting, chances are these copies will get out of
sync! how is it better to call sprintf() instead of snprintf() ?
What is there to gain ?
I suspect any actual implementation is going to use much of the same
underlying code for all the *printf functions. And even if the code
is duplicated, any discrepancy between the length determined by
snprintf() and the length determined by sprintf() would be a bug in
the implementation. If you're unwilling to assume that the
implementation gets things right, you probably shouldn't be using it
in the first place. If you happen to know of a specific bug in some
implementation, it can make sense to guard against it in your code
(*and* submit a bug report to the implementer), but guarding against
implementation bugs in general is a waste of time. Or did I miss your
point?
Charlies point, AFAICS, is that you easily can make a slip of the kind
"Oh, I will always copy over the format string" and then forget it
once. This may lead to exactly the buffer overrun which was to be
avoided in the first place.
As Dan referred to the const char * fmt in both cases, this point is
moot here; but in general, I agree that it certainly does not hurt to
always use snprintf...
Exactly. The bold programmer is his own worst enemy.
In Chris Torek's example snprintf() is called with a variable format string.
This is *bad* practice. It prevents casual and compiler assisted verification
of parameter consistency. The unknown format string fmt points to may well
refer to more than 2 parameters and not necessarily of the correct type.
Calling snprintf() twice with the same arguments may well produce different
output in this case (or much worse UB of course).
What I was refering to in my reply was not snprintf() and sprintf()
implementations getting out of sync: they most likely share a common
implementation. But the programmer's code for those 2 calls runs the risk of
differentiating of time, via ill-advised maintenance. Call it the law of
evolution applied to C code. Even from day one, the 2 calls may have been
created different by mistake.
It would be much less error-prone to wrap those in some kind of loop executed
twice with a single snprintf() statement.
GNU defines asprintf() for this purpose. The implementation is straightforward
and can be made an easy addition to projects targetted at non gcc platforms.
int asprintf(char **strp, const char *fmt, ...);
int vasprintf(char **strp, const char *fmt, va_list ap);
strp will receive a pointer to storage allocated via malloc(). This is exactly
what Chris Torek does in his example, except more general and usable.
Chqrlie.