Reputation: 439
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
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