stefv
stefv

Reputation: 439

Call to snprintf and vsnprintf inside a variadic function

I'm trying to use variadic functions inside a variadic function. I check many examples on Internet and Stack Overflow but I can't find my mistake.

When I'm running my program using Visual Studio, I have an access violation when it's calling snprintf.

Here the header:

#pragma once
#include <cstdarg>
class Console
{
   public:
     static void writeLine(const char *s, ...);

   private:
     Console() = delete;
    ~Console() = delete;
};

The class:

#include "Console.h"
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <iostream>

void Console::writeLine(const char *s...)
{
    va_list arg1, arg2;

    // Search the total length
    va_start(arg1, s);
    va_copy(arg2, arg1);
    int length = snprintf(nullptr, 0, s, arg1);
    va_end(arg1);

    size_t size = length + 1;
    char *szBuff = new char[size]; // note +1 for terminating null byte

    // Format the string
    vsnprintf(szBuff, size, s, arg2);
    va_end(arg2);

    std::cout << (const char*)szBuff << std::endl;

   delete(szBuff);
}

And the main program:

#include "Console.h"
#include <iostream>

int main()
{
   Console::writeLine("Example with an int (%d) and a string(%s)", 10, "my string");
}

I'm sure I did a stupidity, but I can't see why it's not working.

EDIT

The cout call is just un example, I'm using a function from Windows to write to the console of Visual Studio. It's why, I'm doing this class: to format the data before to write the result to the console.

Upvotes: 1

Views: 2759

Answers (1)

Remy Lebeau
Remy Lebeau

Reputation: 597166

You are using the wrong function to calculate the size of your buffer. snprintf() does not take a va_list as input. Also, Microsoft's implementation of vsnprintf() is not defined as accepting a NULL buffer as input, like snprintf() does. You need to use _vscprintf() instead:

_vscprintf returns the number of characters that would be generated if the string pointed to by the list of arguments was printed or sent to a file or buffer using the specified formatting codes. The value returned does not include the terminating null character.

Also, you are not freeing your buffer correctly. Since you use new[] to allocate it, you need to use delete[] to free it.

Try this instead:

void Console::writeLine(const char *s, ...)
{
    va_list arg1, arg2;

    va_start(arg1, s);

    // Search the total length
    va_copy(arg2, arg1);
    size_t size = _vscprintf(s, arg2) + 1; // note +1 for terminating null byte
    va_end(arg2);

    char *szBuff = new char[size];

    // Format the string
    vsnprintf(szBuff, size, s, arg1);

    va_end(arg1);

    std::cout << szBuff << std::endl;

    delete[] szBuff;
}

Upvotes: 4

Related Questions