c - snprintf usage for making up formatted strings - Stack Overflow
c - snprintf() without format specifier? - Stack Overflow
c - Using snprintf to print an array? Alternatives? - Stack Overflow
examples of snprintf advantages over printf?
The 2x call to snprintf() is a common idiom.
... has another problem?
Problems lie in the corners
Format maintenance
The below suffers from a repeated format - prone to breaking as code ages and and only one line is changed.
// Oops!
int need_space = snprintf(NULL, 0, "abs %s", "fgh") + 1;
char *const str = malloc(need_space * sizeof(char));
int written = snprintf(str, need_space, "abs %s ", "fgh");
Did you notice the difference?
Better to state the format once.
#define FMT_ABS_S "abs %s"
int need_space = snprintf(NULL, 0, FMT_ABS_S, "fgh");
char *const str = malloc(sizeof *str * (need_space + 1u));
int written = snprintf(str, need_space + 1, FMT_ABS_S, "fgh");
Volatility
Code needs to insure the values do not change (non-volatile) between the 2 calls and special concern arise in multi-threaded applications.
Error checking
Code lacked checks. Yet even with checks, how to even handle unexpected results - perhaps just bail?
static const char *fmt_s = "abs %s";
int length = snprintf(NULL, 0, fmt_s, "fgh");
if (length < 0) {
Handle_EncodingError();
}
char *str = malloc(sizeof *str * (length + 1u));
if (str == NULL) {
Handle_OutOfMemory();
}
int written = snprintf(str, length + 1, fmt_s, "fgh");
if (written < 0 || written > length) {
Handle_Error();
}
...
free(str);
Going twice though
2 calls can be wasteful in select situations, yet commonly the impact is less than thought. @Jonathan Leffler
Yet for me, the "what to do if allocation fails" is a show stopper anyways and code reports the error and maybe exit.
Selectively, once is enough
When the s*printf() format is tightly controlled, I see 1 call as sufficient.
// int to string
#define LOG2_N 28
#define LOG2_D 93
// Number of char needed for a string of INT_MIN is log10(bit width) + 3
#define INT_SIZE ((sizeof(int)*CHAR_BIT-1)*LOG2_N/LOG2_D + 3)
char s[INT_SIZE * 2]; // I like to use 2x to handle locale issues, no need to be stingy here.
int len = snprintf(s, sizeof s, "%d", i);
if (len < 0 || (unsigned) len >= sizeof s) {
Handle_VeryUnusualFailure();
}
In addition to @chux precise answer, it should be noted that the posted code has potential undefined behavior:
char buf[20] = ""; // initialization is optional
char *cur = buf, * const end = buf + sizeof buf; // cumbersome combined definitions
cur += snprintf(cur, end-cur, "%s", "foo"); // cur may be increased beyond the end of the array
printf("%s\n", buf); // no problem here
if (cur < end) { // undefined behavior if cur points beyond the end of the array
cur += snprintf(cur, end-cur, "%s", " bar"); // again cur may be increased too far.
}
printf("%s\n", buf); // OK
free(str); // definition for str is not posted
If snprintf truncates the output, cur will be increased to point beyond the end of the array buf, which has undefined behavior. Comparing cur and end is meaningless if they do not point the same array or to the element just after the array.
It is easy to fix these problems:
char buf[20];
size_t size = sizeof buf;
size_t pos = 0;
int n = snprintf(buf + pos, size - pos, "%s", "foo");
if (n < 0) {
// handle this unlikely error
*buf = '\0';
} else {
pos += n;
}
printf("%s\n", buf);
if (pos < size) {
n = snprintf(buf + pos, size - pos, "%s", " bar");
}
printf("%s\n", buf);
No, you don't have to, technically. But it's better practice to do so, because without a constant format string, your format string remains modifiable thus your code will be more prone to format string attacks.
Ah, and also use sizeof(duplicateId) instead of a constant 10 - also for security reasons (in order to avoid future buffer overflows when changing the size of the output buffer of sprintf).
No you dont, but it's generally considered a good idea especially if there's any chance of passing user-input text to snprintf(). If the user enters a string with % in it otherwise, there will be trouble:
const char *userString = "%";
snprintf(duplicateId, sizeof duplicateIt, userString); /* BAD */
const char *userString = "%s";
snprintf(duplicateId, sizeof duplicateIt, "%s", userString); /* GOOD. */
No, there's no formatting specifier for that.
Sure, use a loop. You can use snprintf() to print each double after the one before it, so you never need to copy the strings around:
double a[] = { 1, 2, 3 };
char outbuf[128], *put = outbuf;
for(int = 0; i < sizeof a / sizeof *a; ++i)
{
put += snprintf(put, sizeof outbuf - (put - outbuf), "%f ", a[i]);
}
The above is untested, but you get the general idea. It separates each number with a single space, and also emits a trailing space which might be annoying.
It does not do a lot to protect itself against buffer overflow, generally for code like this you can know the range of the inputs and make sure the outbuf is big enough. For production code you would need to think about this of course, the point here is to show how to solve the core problem.
I decided to go with this:
int ptr = 0;
for( i = 0; i < size; i++)
{
ptr += snprintf(outbuf + ptr, sizeof(outbuf) - ptr, "%.15f ", values[i]);
}
slightly different, but to the same effect as in @unwind 's solution. I got this idea from the reference page for snprintf()
I know what snprintf does and how it works but I think I really need some examples of how it would be used in terms of efficiency in a program. Any help would be appreciated. :D
Edit: so printf and snprintf cannot be compared in terms of efficiency..oops. Still looking for examples for snprintf and maybe sprint f and why you would use it. Thank's guys!!