I'm getting some unexpected result when using vsnprintf. In the code below, I used snprintf and passed a null destination pointer to find out how much space it needs
#define long_string 256
typedef char STRING_VARIABLE [long_string + 1];
void SAFE_snprintf( char * buffer, char * format ,... )
{
va_list args;
va_start(args, format);
int m = vsnprintf (0, 0, format, args);
printf("m = %d\n", m);
if (m < 0)
{
perror ("snprintf failed");
abort ();
}
// Allocating memory
char *bufferString = (char *) malloc (n - 1);
if (!bufferString)
{
perror ("malloc failed");
abort ();
}
m = vsnprintf (bufferString, (n - 1), format, args);
if (m < 0)
{
perror ("vsnprintf failed");
abort ();
}
strcpy(buffer, bufferString);
free (bufferString);
va_end(args);
}
int main(int argc, char * argv[])
{
char InputString [] = "Hello";
STRING_VARIABLE bufferStrings;
char format [] = "%s_test";
int n = snprintf (0, 0, "%s_test", InputString);
if (n < 0)
{
perror ("vsnprintf failed");
abort ();
}
printf("n = %d", n);
SAFE_snprintf(bufferStrings, format , InputString);
return 0;
}
The above code returns
n = 7
m = 10
I'm not sure why snprintf is returning 7 (which is correct), and vsnprintf is returning 10. Which I assume is wrong or of course my understanding is flawed somewhere.
I wanted to use snprintf "safely" i.e. by avoiding string truncation. The idea was to determine the string size before using snprintf. This meant using it twice. Once to workout the size, then allocate appropriate memory to use snprintf again. Ofcourse there are a variable amount of inputs needed as any printf functions. So wanted to use vsnprintf to create a variadic function which does the aforementioned.
I know there is still the issue of checking if the original string being passed isn't too long and will not result in string truncation. But confused to why vsnprintf is not working as expected
It's invalid to re-use va_list
for another call.
va_list args;
va_start(args, format);
vsnprintf(..., args);
va_end(args); // basically you have to call it
Call va_copy
or va_start
after it again before calling another v*
function.
va_list args;
va_start(args, format);
vsnprintf(..., args);
va_end(args);
va_start(args, format);
vsnprintf(..., args);
va_end(args);
or
va_list args, args2;
va_start(args, format);
vsnprintf(..., args);
va_copy(args2, args);
va_end(args);
vsnprintf(..., args2);
va_end(args2);
Your buffer is limited to 256 characters long_string 256
, so it does not solve any problem and strcpy(buffer, bufferString);
is very unsafe.
Do not use typedef
arrays - they are very confusing. Prefer a structure.
Overall, you seem to want to implement asprintf
- see sprintf() with automatic memory allocation? , https://man7.org/linux/man-pages/man3/asprintf.3.html . Maybe asprintf
is going to be standard https://en.cppreference.com/w/c/experimental/dynamic .