I have the following statement:
vsnprintf(target, size - 1, "%ls_%ls", str16_1, str16_2);
Why does this fail on gcc?
I used this on Windows like this:
vsnprintf(target, size - 1, "%S_%S", str16_1, str16_2);
and it's working as expected. On gcc documentation I found that %S is synonym with %ls, but I must not use it. I tried also with %S, but is not working. I use this in a function with variable argument list. Is it possible to not work because I change the format variable that I pass to va_start? I must search %S and replace it with %ls in format variable.
The function is something like:
void f(const char* format, ...){
char* new_format = format with %S replaced with %ls;
va_list argptr;
va_start(args, format);
vsnprintf(str, size-1, new_format, argptr);
}
I checked and new_format is correct.
Thank you!
Try using snprintf, the reason being vsnprintf. vsnprintf takes an argument of type va_list, not a literal variadic argument list. For example:
va_list ap;
va_start (ap, first_arg_in_this_function);
vsnprintf (buf, size, format_str, ap);
va_end (ap);
Whereas with sprintf:
snprintf (buf, size, format_str, x, y);
Use v*printf when...
Making wrappers around printf style functions
Variadic macros are not an option
Otherwise just use *printf
Your use of va_start is incorrect. In this statement:
va_start(args, new_format);
you are not referring to the format parameter of the f() function. The second argument to va_start() must refer to a parameter in the formal parameter list of the function. Anything else is likely undefined behaviour.
The compiler uses the named formal parameter in va_start() to determine where to start looking for the variable argument list in the function call. It doesn't automatically know where you put ... in the argument list (perhaps you might expect that it should, but that's not how it works).
I looked up %ls for vsnprintf and found that this is the format specifier for printing/formatting a string of wide characters i.e. wide_t *p = L"Hello world!";
It took a bit of playing and googling wide character usage in C++ (I liked the following page: http://www.linux.com/archive/feed/51836), but I think I figured out your problem.
If you pass in a char string to %ls then it doesn't expand, but if you pass in a wchar_t string to %ls then it prints.
Consider the following example code I based on your information:
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include <wchar.h>
char str[100];
void f (const char *format,
...)
{
va_list args;
va_start(args, format);
vsnprintf(str, sizeof(str), format, args);
va_end(args);
}
int
main ()
{
char *p1 = "1234";
char *p2 = "abcd";
wchar_t *pw1 = L"9876";
wchar_t *pw2 = L"wxyz";
f("%d_%d", 120, 199);
printf("numbers: %s\n", str);
f("%s_%s", p1, p2);
printf("char*: %s\n", str);
f("%ls_%ls", p1, p2);
printf("wide char* with char* input: %s\n", str);
f("%ls_%ls", pw1, pw2);
printf("wide char* with wide char* input: %s\n", str);
return (0);
}
I compiled this with g++.
make newtest.exe
g++ -g -c -MD -Wall -Werror newtest.cxx
g++ -o newtest.exe newtest.o -lc -lrt
Compilation finished at Thu Jul 29 08:54:57
Output is below:
[SUSE10.1]:201> newtest.exe
numbers: 120_199
char*: 1234_abcd
wide char* with char* input:
wide char* with wide char* input: 9876_wxyz
Use snprintf.
What is your valist type? The correct type for variable list arguments is va_list with an underscore, no?
Because I use this on Mac I found a work-around:
How to "pass on" a variable number of arguments to NSString's +stringWithFormat:
It seems that vsnprintf can't handle 16 bits string. Maybe because wchar_t isn't 16 bits.
Related
In this example this code although compiles it doesn't produce correct result:
void encapsulatePrintf(const char *str, ...) {
va_list argptr;
va_start(argptr, str);
printf(str, argptr);
va_end(argptr);
}
and then in main: encapsulatePrintf("test str: %i - %s", 22, "test2");
the result is random bytes form somewhere in memory: test str: 2293428 - á "
but when I change the function from printf to vfprintf(stdout, str, argptr);
all the output is ok.
What's going on here ?
printf() doesn't take va_list as argument but rather a variable list of arguments while vprintf() takes a va_list as argument and not a variable list of arguments. Basically, when you called printf() using
printf(str, argptr);
you invoked undefined behavior: the first argument promised that you would pass an int and a char* but you passed, instead, a va_list. The types of the arguments passed to printf() have to match the specification in the format string.
I'm using VS2010 Pro compiler, when I build on x64 I get below compilation error. Compiles perfectly on x86.
error C2704: '' : __va_start intrinsic only allowed in varargs
Declaration of method:
int foo(char* buf, int maxChar, const char*& fmt);
definition:
int foo(char* buf, int maxChar, const char*& fmt)
{
int numChar = 0;
if (fmt)
{
va_list plist;
va_start(plist, fmt);
numChar = _vsnprintf(buf, maxChar, fmt, plist);
va_end(plist);
}
return numChar;
}
What is the meaning of the error? How to fix this?
I think it means pretty much what it says. The compiler won't allow you to use va_start, va_arg, etc, except in a variable argument function. Using va_start outside of a vararg function makes no sense.
This doesn't define a variable argument function:
int foo(char* buf, int maxChar, const char*& fmt)
This does:
int foo(char* buf, int maxChar, const char*& fmt, ...)
On x86, all arguments are passed on the stack, and it's semantically safe (albeit incorrect) to use va_start and friends to get "arguments".
However, on amd64 (and most likely on ARM), some arguments are passed via registers. In this case, using va_start in a function that isn't declared to take variable arguments is semantically unsafe - va_start would index into invalid memory.
You used a varargs macro in a function with a fixed number of arguments; MSDN link to the error.
following is the implementation of my method
static VALUE myMethod(VALUE self, VALUE exc, const char* fmt, ...) {
// Need to get all the arguments passed to this function and print it
}
function is called as follows:
myMethod(exception, ""Exception message: %s, Exception object %d",
"Hi from Exception", 100);
Can you provide the code for myMethod() that will access all the arguments and print them out.
Thanks in advance.
The va_start and va_arg macro's are used to get the variable arguments in a function.
An example can be found on the Microsoft site: http://msdn.microsoft.com/en-us/library/kb57fad8(v=vs.71).aspx
In your case it's a bit trickier, since you need to parse the format string to exactly know how many arguments should be given and of which type they are. Luckily, the CRT contains a function for that. The vfprintf function can be given a va_list (which you get from va_start). vfprintf will use this one to process all the extra arguments. See http://www.cplusplus.com/reference/clibrary/cstdio/vfprintf/ for an example.
One way is to use vsnprintf().
Sample code:
char buf[256];
va_list args;
va_start(args, fmt);
if(vsnprintf(buf, sizeof(buf), fmt, args) > 0)
fputs(buf, stderr);
va_end(args);
You need to use va_start and va_arg macros to get the arguments.
You can take a look at this - it has some examples.
http://www.go4expert.com/forums/showthread.php?t=17592
void printLine(const wchar_t* str, ...)
{
// have to do something to make it work
wchar_t buffer[2048];
_snwprintf(buffer, 2047, ????);
// work with buffer
}
printLine(L"%d", 123);
I tried
va_list vl;
va_start(vl,str);
and things like this but I didn't find a solution.
Here's a simple C code that does this, you will have to include stdarg.h for this to work.
void panic(const char *fmt, ...){
char buf[50];
va_list argptr; /* Set up the variable argument list here */
va_start(argptr, fmt); /* Start up variable arguments */
vsprintf(buf, fmt, argptr); /* print the variable arguments to buffer */
va_end(argptr); /* Signify end of processing of variable arguments */
fprintf(stderr, buf); /* print the message to stderr */
exit(-1);
}
The typical invocation would be
panic("The file %s was not found\n", file_name); /* assume file_name is "foobar" */
/* Output would be:
The file foobar was not found
*/
Hope this helps,
Best regards,
Tom.
What you want to use is vsprintf it accepts the va_list argument and there is sample
code on MSDN in the link.
EDIT:
You should consider _vsnprintf which will help avoid buffer overrun issues that vsprintf will happily create.
Typically one calls into a variable args version of the function, that accepts va_list. For example _snwprintf internally calls _vsnwprintf; try calling that.
Other people have already pointed you to the vprintf-family of functions, but this also (not surprisingly) is answered by the comp.lang.c FAQ, if you want to familiarize yourself with the other FAQ entries. (They're worth reading, IMO.)
How can I write a function that takes a format string and a variable number of arguments, like printf, and passes them to printf to do most of the work?
I have a class that holds an "error" function that will format some text. I want to accept a variable number of arguments and then format them using printf.
Example:
class MyClass
{
public:
void Error(const char* format, ...);
};
The Error method should take in the parameters, call printf/sprintf to format it and then do something with it. I don't want to write all the formatting myself so it makes sense to try and figure out how to use the existing formatting.
Use vfprintf, like so:
void Error(const char* format, ...)
{
va_list argptr;
va_start(argptr, format);
vfprintf(stderr, format, argptr);
va_end(argptr);
}
This outputs the results to stderr. If you want to save the output in a string instead of displaying it use vsnprintf. (Avoid using vsprintf: it is susceptible to buffer overflows as it doesn't know the size of the output buffer.)
have a look at vsnprintf as this will do what ya want http://www.cplusplus.com/reference/clibrary/cstdio/vsprintf/
you will have to init the va_list arg array first, then call it.
Example from that link:
/* vsprintf example */
#include <stdio.h>
#include <stdarg.h>
void Error (char * format, ...)
{
char buffer[256];
va_list args;
va_start (args, format);
vsnprintf (buffer, 255, format, args);
//do something with the error
va_end (args);
}
I should have read more on existing questions in stack overflow.
C++ Passing Variable Number of Arguments is a similar question. Mike F has the following explanation:
There's no way of calling (eg) printf
without knowing how many arguments
you're passing to it, unless you want
to get into naughty and non-portable
tricks.
The generally used solution is to
always provide an alternate form of
vararg functions, so printf has
vprintf which takes a va_list in place
of the .... The ... versions are just
wrappers around the va_list versions.
This is exactly what I was looking for. I performed a test implementation like this:
void Error(const char* format, ...)
{
char dest[1024 * 16];
va_list argptr;
va_start(argptr, format);
vsprintf(dest, format, argptr);
va_end(argptr);
printf(dest);
}
You are looking for variadic functions. printf() and sprintf() are variadic functions - they can accept a variable number of arguments.
This entails basically these steps:
The first parameter must give some indication of the number of parameters that follow. So in printf(), the "format" parameter gives this indication - if you have 5 format specifiers, then it will look for 5 more arguments (for a total of 6 arguments.) The first argument could be an integer (eg "myfunction(3, a, b, c)" where "3" signifies "3 arguments)
Then loop through and retrieve each successive argument, using the va_start() etc. functions.
There are plenty of tutorials on how to do this - good luck!
Simple example below. Note you should pass in a larger buffer, and test to see if the buffer was large enough or not
void Log(LPCWSTR pFormat, ...)
{
va_list pArg;
va_start(pArg, pFormat);
char buf[1000];
int len = _vsntprintf(buf, 1000, pFormat, pArg);
va_end(pArg);
//do something with buf
}
Using functions with the ellipses is not very safe. If performance is not critical for log function consider using operator overloading as in boost::format. You could write something like this:
#include <sstream>
#include <boost/format.hpp>
#include <iostream>
using namespace std;
class formatted_log_t {
public:
formatted_log_t(const char* msg ) : fmt(msg) {}
~formatted_log_t() { cout << fmt << endl; }
template <typename T>
formatted_log_t& operator %(T value) {
fmt % value;
return *this;
}
protected:
boost::format fmt;
};
formatted_log_t log(const char* msg) { return formatted_log_t( msg ); }
// use
int main ()
{
log("hello %s in %d-th time") % "world" % 10000000;
return 0;
}
The following sample demonstrates possible errors with ellipses:
int x = SOME_VALUE;
double y = SOME_MORE_VALUE;
printf( "some var = %f, other one %f", y, x ); // no errors at compile time, but error at runtime. compiler do not know types you wanted
log( "some var = %f, other one %f" ) % y % x; // no errors. %f only for compatibility. you could write %1% instead.
Have a look at the example http://www.cplusplus.com/reference/clibrary/cstdarg/va_arg/, they pass the number of arguments to the method but you can ommit that and modify the code appropriately (see the example).