I wrote a very simple test code to test vsnprintf, but in xcode and visual studio environment, the results are very different. The test code is as follows:
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include <string.h>
#include <cstdarg>
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args);
printf("%s\n", defaultBuf);
va_end(args);
}
int main(int argc, const char* argv[])
{
// if you uncomment this line(std::cout ...), it will crash at vsnprintf in xcode
std::cout << "Tests...!\n";
p("Create:%s(%d)", "I'm A String", 0x16);
return 0;
}
this is the output in visual studio :
Tests...!
Create:I'm A String(22)
Create:I'm A String(22)
This is normal and doesn't seem to be a problem. But the same code, I created a macos command line project, pasted this code in, something strange happened, when the code is executed to vsnprintf, it will start EXC_BAD_ACCESS directly.
What's more outrageous is that if I comment out the std::cout in the main function, it will not crash, but the output is wrong. So the question is, what is the reason for this difference, shouldn't these functions all be functions of the C standard library, and their behavior should be constrained by the standard library? Or is my usage wrong? the output when i delete std::cout:
Create:I'm A String(22)
Create:\310\366\357\277\367(3112398)
Program ended with exit code: 0
If only one is right, is xcode right or visual studio is right, in the end I used is the latest xcode 14, visual studio 2022。
CodePudding user response:
You must reinitialize the va_list
between calls to vsprintf
. Failure to do so is undefined behavior.
See https://en.cppreference.com/w/c/variadic/va_list :
If a
va_list
instance is created, passed to another function, and used via va_arg in that function, then any subsequent use in the calling function should be preceded by a call tova_end
.
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
vsprintf(defaultBuf, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
va_start(args, fmt);
vsnprintf(defaultBuf, DefaultLength, fmt, args);
va_end(args);
printf("%s\n", defaultBuf);
}
CodePudding user response:
void p(const char* fmt, ...)
{
static const int DefaultLength = 256;
char defaultBuf[DefaultLength] = { 0 };
va_list args;
va_start(args, fmt);
va_list args_r;
va_copy(args_r, args);
vsprintf(defaultBuf, fmt, args);
printf("%s\n", defaultBuf);
memset(defaultBuf, 0, sizeof(defaultBuf));
vsnprintf(defaultBuf, DefaultLength, fmt, args_r);
printf("%s\n", defaultBuf);
va_end(args_r);
va_end(args);
}