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
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.
Suppose I want to make a function that recursively parses a variadic argument list, by letting each invocation of the function read the next argument? After handing the va_list to the next function, I am not intending to continue using the va_list in the calling function. Is the following code ok:
void VarArgRecursive( va_list args ) {
int nextArg = va_arg(args, int);
if( nextArg != -1 ) {
printf("Next arg %d\n", nextArg);
VarArgRecursive(args);
}
}
void VarArgFunc( int firstArg, ... ) {
va_list args;
va_start(args, firstArg);
VarArgRecursive(args);
va_end(args);
}
int main (int argc, char * const argv[]) {
VarArgFunc(20, 12, 13, -1);
return 0;
}
The code compiles on my system, and the output is as expected:
Next arg 12
Next arg 13
So, is this practice OK? I have searched the list, and found that after handing the va_list over to the next function, the contents of the va_list in the calling function is undefined. That shouldn't matter for my usage, as I will not continue using the va_list after handing it over to the next (well, actually, the same) function. I have also checked this page:
http://c-faq.com/varargs/handoff.html
...which shows that my way of handing over the va_list to the next function is OK. What it doesn't say, is whether it is OK to hand the va_list over to yet another function after reading one arg, and expect the called function to read the next arg. If there are c++ -specific answers to this question, that is also ok, since it will be used in a c++ program.
You can pass it however many times you like, but you cannot "use" the va_list more than once. When consumed, the va_list may be modified and using it again is undefined behavior per the C++ spec.
If you want to use it more than once, call va_copy to clone the va_list prior to consuming it, then pass the copy.
However, in your case what you're doing is acceptable. The problem arises when you attempt to pass the va_list from the beginning to another function.
TraceMessage is an WinAPI function with variable number of arguments. It is a tracing function, with a notation similar to printf, which generates a trace message in Windows tracing. The weird part here is that it receive a format string as part of the ellipsis, not as a dedicated argument.
It is possible to 'override' this function with a function of my own, which then needs to call TraceMessageVa (which is the same as TraceMessage, just with va_args rather than ellipsis).
So far so good; but now I want to access the traced message using a sprintf-like function, which has the format string out of the ellipsis. Thus I need to
- get the format string argument out of the ellipsis ;
- create a new va_list without the first argument.
Any idea about to how do it? Solutions specific to Visual Studio compiler are also acceptable. Thanks!
With a va_list you can pass it to a function which takes a va_list after having used va_arg on it already to have extracted one or more arguments. The va_list will then act like it "contains" only the rest of the arguments.
I have no experience with TraceMessage itself, but I've given an example using standard vprintf and a test function. You should be able to adapt as appropriate.
E.g.
#include <stdio.h>
#include <stdarg.h>
void test(int a, ...)
{
va_list va;
const char* x;
va_start(va, a);
x = va_arg(va, const char*);
vprintf(x, va);
va_end(va);
}
int main(void)
{
test(5, "%d\n", 6);
return 0;
}
This question already has answers here:
Closed 13 years ago.
Possible Duplicate:
C Programming: Forward variable argument list.
What I'd like to do is send data to a logging library (that I can't modfify) in a printf kind of way.
So I'd like a function something like this:
void log_DEBUG(const char* fmt, ...) {
char buff[SOME_PROPER_LENGTH];
sprintf(buff, fmt, <varargs>);
log(DEBUG, buff);
}
Can I pass varargs to another vararg function in some manner?
You can't forward the variable argument list, since there's no way to express what's underneath the ... as a parameter(s) to another function.
However you can build a va_list from the ... parameters and send that to a function which will format it up properly. This is what vsprintf is for. Example:
void log_DEBUG(const char* fmt, ...) {
char buff[SOME_PROPER_LENGTH];
va_list args;
va_start(args, fmt);
vsprintf(buff, fmt, args);
va_end(args);
log(DEBUG, buff);
}
You can send it to another function that takes a va_list as an argument. There is no other way, short of resorting to hand crafted asm, or doing some kind of horrifying guessing game to figure out the 'number' of parameters.
This would work:
void log_DEBUG(const char* fmt, ...)
{
va_list va;
va_start(va,fmt);
char buff[blah];
vsprintf(buff,fmt,va);
log(DEBUG,buff);
va_end(va);
}
Basically, whenever you write a function that takes ..., you should write another version that takes a va_list - its the polite thing to do if you want to enable this type of chaining call.
This is why you have the vprintf family of functions.
For your specific requirement, you can use vsprintf. My C/C++ is too rusty to recall if there's a straightforward way to do it when the other function isn't designed for it (without getting into ugly stack manipulation), but I tend to think not.
Not in standard C++.
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?