I've tried a lot of solutions, but none of them is working.
printf("Test : %d", 123);
std::cout << "Test" << 123 << std::endl;
...
Actually I've setup my project's debugger like this, I'm able to write in the console using OutputDebugStringA("Test"); but this function doesn't accept more than one parameter.
How can I print something like this : ("Test : %d", 123)?
Bogy's answer is on the right track but I don't like the allocation in GetWC which looks like a memory leak, and it uses unsafe functions, try this:
void Debug::Log(const wchar_t *format, ...)
{
wchar_t buffer[BUFFER_LENGTH];
va_list args;
va_start(args, format);
_vsnwprintf_s(buffer, BUFFER_LENGTH, _TRUNCATE, format, args);
va_end(args);
buffer[BUFFER_LENGTH - 1] = '\0'; //prevent buffer overflow
OutputDebugString(buffer);
}
Usage like:
Debug::Log(L"Hello %S\n", "sailor");
I found this code in a C++ training on Pluralsight that I am using for Windows 8 (you just say TRACE("Test : %d", 123); to use it):
#pragma once
#include <assert.h>
#define ASSERT assert
#ifdef _DEBUG
inline auto Trace(wchar_t const * format, ...) -> void
{
va_list args;
va_start(args, format);
wchar_t buffer[256];
ASSERT(-1 != _vsnwprintf_s(buffer, _countof(buffer) - 1, format, args));
va_end(args);
OutputDebugString(buffer);
}
#endif
struct Tracer
{
char const * m_filename;
unsigned m_line;
Tracer(char const * filename, unsigned const line) :
m_filename{ filename },
m_line{ line }
{
}
template <typename... Args>
auto operator()(wchar_t const * format, Args... args) const -> void
{
wchar_t buffer[256];
auto count = swprintf_s(buffer, L"%S(%d): ", m_filename, m_line);
ASSERT(-1 != count);
ASSERT(-1 != _snwprintf_s(buffer + count, _countof(buffer) - count, _countof(buffer) - count - 1, format, args...));
OutputDebugString(buffer);
}
};
#ifdef _DEBUG
#define TRACE Tracer(__FILE__, __LINE__)
#else
#define TRACE __noop
#endif
I've finally found this solution (here and here) :
Debug.cpp:
#pragma once
#include "pch.h"
#define BUFFER_LENGTH 1024
//char* to wchar_t*
const wchar_t *GetWC(const char *c)
{
const size_t cSize = strlen(c) + 1;
wchar_t* wc = new wchar_t[cSize];
mbstowcs(wc, c, cSize);
return wc;
}
void Debug::Log(const char *format, ...)
{
char buffer[BUFFER_LENGTH];
va_list args;
va_start(args, format);
vsnprintf(buffer, BUFFER_LENGTH, format, args);
va_end(args);
buffer[BUFFER_LENGTH - 1] = '\0'; //prevent buffer overflow
OutputDebugString(GetWC(buffer));
}
Debug.h:
class Debug{
public:
static void Log(const char *format, ...);
};
We can use it like printf function:
Debug::Log("Test : %d", 123);
Related
I have the following code to append a buffer using vsnprintf().
#include <stdio.h>
#include <stdarg.h>
using namespace std;
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_start(arg, format);
vsnprintf(buffer, sizeOfBuffer, format, arg);
va_end(arg);
}
int main()
{
char buffer[1000] = { 0 };
const char* abc = "abc";
const char* def = "def";
MyPrintFunc(buffer, 1000, "%s", abc);
MyPrintFunc(buffer, 1000, "%s%s", buffer, def);
printf("%s\n", buffer);
return 0;
}
It gave different output on both Windows and Linux.
On Windows (using msvc-14.0 compiler), it give desired output of abcdef.
But on Linux (using gcc-5.4), it only print output of def.
How can I get the correct output?
Don't use the same buffer as both an output and input to vsnprintf.
Thanks everyone for the input.
My solution to this is to create a copy of the buffer if user of the MyPrintFunc() used it to append buffer:
void MyPrintFunc(char *buffer, size_t sizeOfBuffer, const char* format, ...)
{
va_list arg;
va_list arg_copy;
va_start(arg, format);
va_copy(arg_copy, arg);
if (buffer == va_arg(arg, char*))
{
char temp[strlen(buffer)];
strcpy(temp, buffer);
MyPrintFunc(buffer, sizeOfBuffer, format, temp, va_arg(arg,char*));
}
else
{
vsnprintf(buffer, sizeOfBuffer, format, arg_copy);
}
va_end(arg);
va_end(arg_copy);
}
I need to translate, vswscanf function from c to c++
using wide string stream and var arg,
can you help me ?
#include <stdarg.h>
#include <wchar.h>
void GetWideMatches ( const wchar_t * str, const wchar_t * format, ... )
{
va_list args;
va_start (args, format);
vswscanf (str, format, args);
va_end (args);
}
int main ()
{
int val;
wchar_t buf[100];
GetWideMatches ( L"99 bottles of beer on the wall", L" %d %ls ", &val, buf);
wprintf (L"Product: %ls\nQuantity: %d\n", buf, val);
return 0;
}
I use the following methods to write to a trace file (inspired by https://stackoverflow.com/a/16046064/283561)
void Tracing::Info( const char* content, ...)
{
va_list paramList;
va_start( paramList, content );
Tracing::AddRecord(boost::log::trivial::info, content, paramList);
va_end( paramList );
}
void Tracing::AddRecord(boost::log::trivial::severity_level sev, const char* content, va_list paramList)
{
int size = vsnprintf(0, 0, content, paramList) + 1;
if (size > 0)
{
boost::scoped_array<char> formattedString(new char[size]);
vsnprintf(formattedString.get(), size, content, paramList);
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> & lg = my_logger::get();
BOOST_LOG_SEV(lg, sev) << formattedString.get();
}
}
If I call the method the following way under Linux (CentOS 7, GCC 4.8.2):
Tracing trace;
trace.Error("No %s root tag found!", rootTag.c_str());
it segfaults at the second call of vsnprintf in AddRecord().
If it's called with a numeric formatter (e.g. %i), it works fine. I've used these methods for years under Windows (VS2008/2010) with no problems.
Am I missing something obvious here?
You can't reuse the va_list like that; you have to use the va_copy() routine to make a new va_list entity, and use that on the second vsprintf; something like:
void Tracing::AddRecord(boost::log::trivial::severity_level sev, const char* content, va_list paramList)
{
va_list parm_copy;
va_copy(parm_copy, paramList);
int size = vsnprintf(0, 0, content, paramList) + 1;
if (size > 0)
{
boost::scoped_array<char> formattedString(new char[size]);
vsnprintf(formattedString.get(), size, content, parm_copy);
boost::log::sources::severity_logger_mt<boost::log::trivial::severity_level> & lg = my_logger::get();
BOOST_LOG_SEV(lg, sev) << formattedString.get();
}
va_end(parm_copy);
}
The problem is that the operation va_arg, which is used in the first vsnprintf alters the state of the va_list, making it invalid for use in the second vsnprintf as-is.
The problem can be easily seen by using a small C program.
#include <stdio.h>
#include <stdarg.h>
void
do_log(const char *item, va_list items)
{
#ifndef EVIL
va_list itemcopy;
va_copy(itemcopy, items);
#else
#define itemcopy items
#endif
int len = vsnprintf(0, 0, item, items);
if (len > 0) {
char buffer[2048];
vsnprintf(buffer, 2047, item, itemcopy);
printf("%s\n", buffer);
}
va_end(itemcopy);
}
int
log_print(const char *item, ...)
{
va_list items;
va_start(items, item);
do_log(item, items);
va_end(items);
return 0;
}
int
main(int argc, char **argv)
{
log_print("These %d %d %d %d", 1, 2, 3, 4);
log_print("Hello %s %s", "Mike", argv[0]);
}
Without -DEVIL, I get:
These 1 2 3 4
Hello Mike ./vargs
if we make with CFLAGS=-DEVIL, I get output (on OSX):
These 4 0 0 1570641464
Hello
On other platforms, it can crash.
I found a way to pass a variable length array in C++. But it fails 'wrap' function in below code. Actually I want to wrap format function in my project.
What am i doing wrong in my code?
test code
#include <iostream>
#include <stdarg.h>
#include <string>
void log(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
int length = _vscprintf(format, argptr);
char* buf_ = new char [length + 1];
int ret = vsnprintf(buf_, 1000, format, argptr);
if (ret >= 0) {
std::cout << buf_ << std::endl;
}
delete[] buf_;
va_end(argptr);
}
void wrap(const char *format, ...)
{
va_list ap;
va_start(ap, format);
log(format, ap);
va_end(ap);
}
int main()
{
log( "direct = %d", 1);
wrap("wrap = %d", 1);
return 0;
}
the result is here.
direct = 1
wrap = 15137088 // what's happen?
I found a way to pass a variable length array in C++
That isn't a variable-length array, and it isn't really idiomatic C++. The ... is a variable-length argument list, and is available in C.
The simplest reasonable way to wrap your log function is the variadic template one, which can simply be written as:
template <typename... Args>
void wrap(const char *format, Args&&... args) {
log(format, std::forward<Args>(args)...);
}
In the log function itself, vsnprintf returns the number of bytes that would have been written, in the event it fills the buffer. So, you can always just call it once with an optimistic buffer size, and grow the buffer if necessary: you don't need the non-standard _vscprintf. That would look something like:
void log(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
static const size_t DefaultSize = 200;
// pick some value that makes sense ^^ here
char buf[DefaultSize];
int rv = vsnprintf(buf, DefaultSize, format, argptr);
if (rv < 0) {
// we can't return errors with this prototype:
// should it throw?
return;
}
if (rv >= DefaultSize) {
vector<char> dynbuf(rv+1);
rv = vsnprintf(&dynbuf[0], dynbuf.size(), format, argptr);
std::cout << &dynbuf[0] << std::endl;
} else {
std::cout << buf << std::endl;
}
va_end(argptr);
}
Note also that wrap knows the types of all its arguments, but that information is discarded when you call the C-style variadic function log. You might consider Boost.Format as a type-safe alternative - as a bonus, it will manage the buffer for you.
Passing a va_list where a variable number of argumets (x, y, z) is expected isn't designed to work.
To achieve what you want, you need to do something like this:
void log_args(const char* format, va_list& argptr)
{
// I'm unsure on this... you may possibly need to make a separate
// copy of the va_list to pass in to each of _vscprintf and vsnprintf.
va_list second;
va_copy(second, argptr);
int length = _vscprintf(format, argptr);
char* buf_ = new char [length + 1];
int ret = vsnprintf(buf_, 1000, format, second);
if (ret >= 0) {
std::cout << buf_ << std::endl;
}
delete[] buf_;
}
void log(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
log_args(argptr);
va_end(argptr);
}
void wrap(const char *format, ...)
{
va_list ap;
va_start(ap, format);
log_args(format, ap);
va_end(ap);
}
In this example 'wrap' and 'log' appear the same... but I presume you want to do something additional in your real wrap function otherwise why would you be asking this question.
In c++11, you can use variadic templates
#include <iostream>
void tprintf(const char* format) // base function
{
std::cout << format;
}
template<typename T, typename... Targs>
void tprintf(const char* format, T value, Targs... Fargs) // recursive variadic function
{
for ( ; *format != '\0'; format++ ) {
if ( *format == '%' ) {
std::cout << value;
tprintf(format+1, Fargs...); // recursive call
return;
}
std::cout << *format;
}
}
int main()
{
tprintf("direct = %\n", 1);
tprintf("wrap = %\n", 1);
return 0;
}
I am porting an application on Mac OS X which was written for Windows.
In this application, there are many instances of _vscwprintf and _vscprintf.
This question helped me to implement _vsprintf on Mac OS X. But same technique for _vswprintf is not working.
Can anyone give the alternative of _vscwprintf on Mac OS X? Or there any equivalent method for this?
Microsoft describes the functions as returning the number of characters that would be used if the string were formatted — note that they are documented as not including the null terminator.
int _vscprintf(
const char *format,
va_list argptr
);
int _vscwprintf(
const wchar_t *format,
va_list argptr
);
Initial answer
These functions can, therefore, be emulated with vsprintf() and vswprintf():
int _vscprintf(const char *format, va_list argptr)
{
return(vsnprintf(0, 0, format, argptr));
}
int _vscwprintf(const wchar_t *format, va_list argptr)
{
return(vswprintf(0, 0, format, argptr));
}
It is up to you whether you remove the leading underscore; I would.
Note that the _vscwprintf() implementation above is flawed; see the code below.
vscprintf() and scprintf()
Apologies: I wrote vsprintf() where I needed to write vsnprintf() (now fixed in the code above); however, vswprintf() already has the safer interface with the buffer length, so there is no vsnwprintf(). There's a reason I prefer to test compile code before (or shortly after) posting it — it's been irksome not having the wherewithal to do so for a couple of days.
Here's an SSCCE for vscprintf() (and scprintf()):
#include <stdio.h>
#include <stdarg.h>
extern int vscprintf(const char *format, va_list argptr);
extern int scprintf(const char *format, ...);
int vscprintf(const char *format, va_list argptr)
{
return(vsnprintf(0, 0, format, argptr));
}
int scprintf(const char *format, ...)
{
va_list args;
va_start(args, format);
int rc = vscprintf(format, args);
va_end(args);
return rc;
}
int main(void)
{
int l = scprintf("%-8s %8d\n", "abc", 123);
if (l > 0)
{
char buffer[l+1];
int n = snprintf(buffer, sizeof(buffer), "%-8s %8d\n", "abc", 123);
printf("%d = %d: %s", l, n, buffer);
}
return 0;
}
Output:
18 = 18: abc 123
vscwprintf() and scwprintf()
It turns out to be harder to simulate _vscwprintf() because the vswprintf() function is not as helpful as the vsnprintf() function. Specifically, vswprintf() reports an error if the formatted string won't fit in the formatted space, whereas vsnprintf() reports the number of characters that would have been needed in the buffer if it was going to fit. Hence, you have to work by trial and error:
#include <stdio.h>
#include <stdarg.h>
#include <wchar.h>
extern int vscwprintf(const wchar_t *format, va_list argptr);
extern int scwprintf(const wchar_t *format, ...);
int vscwprintf(const wchar_t *format, va_list argptr)
{
// Unlike vsnprintf(), vswprintf() does not tell you how many
// characters would have been written if there was space enough in
// the buffer - it just reports an error when there is not enough
// space. Assume a moderately large machine so kilobytes of wchar_t
// on the stack is not a problem.
int buf_size = 1024;
while (buf_size < 1024 * 1024)
{
va_list args;
va_copy(args, argptr);
wchar_t buffer[buf_size];
int fmt_size = vswprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), format, args);
if (fmt_size >= 0)
return fmt_size;
buf_size *= 2;
}
return -1;
}
int scwprintf(const wchar_t *format, ...)
{
va_list args;
va_start(args, format);
int rc = vscwprintf(format, args);
va_end(args);
return rc;
}
int main(void)
{
int l = scwprintf(L"%-8ls %8d\n", L"abc", 123);
if (l > 0)
{
wchar_t buffer[l+1];
int n = swprintf(buffer, sizeof(buffer)/sizeof(buffer[0]), L"%-8ls %8d\n", L"abc", 123);
wprintf(L"%d = %d: %ls", l, n, buffer);
}
return 0;
}
When run, this produces the output
18 = 18: abc 123
(the same as before).
Tested on Mac OS X 10.8.3 using GCC 4.7.3 (which was built on Mac OS X 10.7.5, but that shouldn't cause any problems).
I recommend using open_wmemstream instead. Something like that:
#include <stdio.h>
#include <string>
#include <stdarg.h>
using namespace std;
wstring wstring_format(const wchar_t* format, ...)
{
wchar_t* buf;
size_t size;
FILE* stream = open_wmemstream(&buf, &size);
va_list args;
va_start(args, format);
vfwprintf(stream, format, args);
va_end(args);
fclose(stream);
wstring result(buf, buf + size);
free(buf);
return result;
}