skip to Main Content

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("%sn", defaultBuf);
    
    memset(defaultBuf, 0, sizeof(defaultBuf));
    vsnprintf(defaultBuf, DefaultLength, fmt, args);
    printf("%sn", 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.

enter image description here
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:310366357277367(3112398)
Program ended with exit code: 0

enter image description here

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。

2

Answers


  1. Chosen as BEST ANSWER
    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("%sn", defaultBuf);
        
        memset(defaultBuf, 0, sizeof(defaultBuf));
        vsnprintf(defaultBuf, DefaultLength, fmt, args_r);
        printf("%sn", defaultBuf);
        va_end(args_r);
        va_end(args);
    }
    

  2. 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 to va_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("%sn", defaultBuf);
        
        memset(defaultBuf, 0, sizeof(defaultBuf));
        va_start(args, fmt);
        vsnprintf(defaultBuf, DefaultLength, fmt, args);
        va_end(args);
    
        printf("%sn", defaultBuf);
    }
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search