converting va_list to variable argument? [duplicate] - c

This question already has answers here:
Passing variable arguments to another function that accepts a variable argument list
(11 answers)
Closed 8 years ago.
I have a function log_message it takes variable arguments.
log_message(int level, char *fmt, ...)
now before calling this(log_message) function i have to add new function(_log_message), and new function will call log_message.
_log_message(int level, char *fmt, ...)
new function is also same. when _log_message will call log_message it will convert variable input to va_list. Now i have va_list, i don't wanna change the original one, is there any way to change back to variable input, so i will able to call the original one(log_message).

No, there is no way to turn a va_list back into a list of arguments.
The usual approach is to define a base function which takes a va_list as an argument. For example, the standard C library defines printf and vprintf; the first is a varargs function and the second has exactly the same functionality but takes a va_list instead. Similarly, it defines fprintf and vfprintf. It's trivial to define printf, vprintf and fprintf in terms of vfprintf:
int fprintf(FILE* stream, const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vfprintf(stream, format, ap);
va_end(ap);
return n;
}
int vprintf(const char* format, va_list ap) {
return vfprintf(stdout, format, ap);
}
int printf(const char* format, ...) {
va_list ap;
va_start(ap, format);
int n = vprintf(format, ap);
va_end(ap);
return n;
}
(Similarly for the various exec* functions, which come in both va_list and varargs varieties.)
I'd suggest you adopt a similar strategy.

Related

Is vsprintf() guaranteed not to access va_list if format string makes no % references?

If the format string passed to vsprintf() (and variants thereof) contains no %-references, is it guaranteed that the va_list argument is not accessed?
Put another way, is:
#include <stdarg.h>
#include <stdio.h>
int main ( void ) {
char str[16];
va_list ap; /* never initialized */
(void)vsnprintf(str, sizeof(str), "", ap);
return 0;
}
a standard-conforming program? or is there undefined behavior there?
The example above is obviously silly, but imagine a function which can be called by both a variadic function and a fixed-args function, grossly simplified into something like:
void somefuncVA ( const char * fmt, va_list ap ) {
char str[16];
int n;
n = vsnprintf(str, sizeof(str), fmt, ap);
/* potentially do something with str */
}
void vfoo ( const char * fmt, ... ) {
va_list ap;
va_start(fmt, ap);
somefuncVA(fmt, ap);
}
void foo ( void ) {
va_list ap; /* no way to initialize this */
somefuncVA("", ap);
}
int vsprintf(char * restrict s, const char * restrict format, va_list arg);
If the format string passed to vsprintf() ... contains no %-references, is it guaranteed that the va_list argument is not accessed.
No.
The vsprintf function is equivalent to sprintf, with the variable argument list
replaced by arg, which shall have been initialized by the va_start macro .....
C11dr ยง7.21.6.13
Since the below code does not adhere to the spec, the result is undefined behavior (UB). No guarantees. #Eugene Sh.
va_list ap;
// vv-- ap not initialized
(void)vsnprintf(str, sizeof(str), "", ap);
Is vsprintf() guaranteed not to access va_list if format string makes no % references?
With a properly passed va_list arg, vsprintf() acts like sprintf(). Code like the following is OK. It is permissible to pass extra arguments. Via vsprintf(), they (the extra arguments) are not accessed, yet va_list arg may be accessed.
sprintf(buf, "format without percent", 1.2345, 456)`
If you don't have varargs passed to your function - your function isn't defined with ... as the last parameter - there's simply never any need for any use of va_list or va_start() in that function. If you want to pass an empty set of variable arguments, simply call the varargs function directly without any variable arguments - e.g., printf("\n");.
For example, instead of
void foo ( void ) {
va_list ap; /* no way to initialize this */
somefuncVA("", ap);
}
you can just write
void foo ( void ) {
vfoo("");
}

How to wrap variadic functions using LD_PRELOAD?

I have to perform dynamic linking on a variadic function of following format:
int foo(char *args, const char *f, ...)
Here the number of arguments are variable.
What I want to achieve is that I want to pass the obtained arguments to the original function which I am resolving using dlsym.
If I do not pass all the arguments I keep getting segmentation fault.
Thanks in advance.
I think your problem is not related to LD_PRELOAD or dlopen/dlsym: you simply want to call a variadic function from a variadic function, eg:
int printf (const char *fmt, ...) {
return fprintf (stdout, fmt, my_variadic_parameters);
}
As far as I know, it is not possible, but in carefully designed libraries (which is obviously a minority of them), every variadic function has a counterpart that uses va_list parameter, like printf and vprintf, fprintf and vfprintf:
int printf (const char *fmt, ...) {
va_list ap;
int retval;
va_start (ap, fmt);
retval= vfprintf (stdout, fmt, ap);
va_end (ap);
return retval;
}
int vmyprintf (const char *fmt, va_list pap) {
va_list ap;
int retval;
va_copy (ap, pap);
retval= vfprintf (stdout, fmt, ap);
va_end (ap);
return retval;
}
So you should ask the creator of 'foo' to create a 'vfoo':
int vfoo (char *args, const char *f, va_list v)
Have a look at man va_start, there is a nicely concise example in that man page.
You can treat the dlsym symbol address just you would any other function pointer.
The basic concept behind va_args, is using a control variable in a loop, usually a printf style format string that can be parsed to decide when to exit the call frame building loop. In your case ankit, you need to have some form "is there another argument to place in the call frame" as you build up a va_list. Basically va_start va_arg... va_end.
Again, best explained in code, and the man page has a nice example.
Given
int foo(char *args, const char *f, ...)
the information provided by either args or f ought to tell you how many parameters of which type had been passed by the caller as variadic arguments.
How this info is provided depends on foo's implementation, so see foo() documentation.
A nice example to this is printf(const char * format, ...); All info of what is received as variadic arguments shall be parseable from the 1st parameter, the non-variadic format-"string".
If you fail to gain insight in this, you are lost. In C there is no generic, "built-in" way to gather the number and types of variadic arguments passed.

C vararg recursive function : what is the syntax?

I'm trying to make a recursive function with variable args in C, and I can't seem to pass the args when writing the recursive call.
Code:
void f(const char* s, ...) {
va_list args;
va_start(args, s);
f(s,args);
va_end(args);
}
}
Don't mind the infinite call stack. It's not the point here, so I discarded every other aspect in the code.
A va_list is an implementation-defined way to access arguments of a function you don't know at compile time -- for example (depending on the architecture) a pointer somewhere in the stack frame of the function. You can't use it in place of actual arguments.
If you need to pass on variadic arguments, the typical approach is to have your implementation in a function that takes a va_list argument. The idiomatic way to name that function is to prepend a v to its name. So in the end, you have two functions:
void vf(const char* s, va_list ap) {
// your logic ...
vf(s, ap); // recursive call
}
// just a wrapper:
void f(const char* s, ...) {
va_list args;
va_start(args, s);
vf(s, args);
va_end(args);
}
Note that this passes on a reference to the arguments your function was originally called with. If this is a problem for your logic, you can copy the whole argument list with the va_copy macro.

how to use elipsis (...) [duplicate]

This question already has answers here:
How to pass variable number of arguments to printf/sprintf
(7 answers)
Closed 7 years ago.
i want to write a function in c which uses the elipsis (...) argument, but i have no idea how it works.
i want to do something like this:
void error(const char* fmt, ...);
void error(const char* fmt, ...) {
// fprintf(stderr, fmt, ...); << didnt work!
fprintf(stderr, fmt, /* ??? */);
}
i want to use it like a "normal" printf() call.
error("bla");
error("nr: %d", 42);
error("pi: %f", 3.1415);
how can i access the elipsis as hole thing and pass it to the next function?
The ellipsis does not constitute a "pack" in any way that you can handle or forward directly. The only way you can manage function arguments that don't match any function parameters is via the <stdarg.h> features.
This means that for every variable function foo you should also always have a corresponding function vfoo that consumes a va_list. For example:
#include <stdarg.h>
void foo(const char * fmt, ...);
void vfoo(const char * va_list ap);
The former is typically implemented in terms of the latter:
void foo(const char * fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vfoo(fmt, ap);
va_end(ap);
}
Luckily, printf family of functions follows these rules. So when you want to farm out to a printf function, you actually use the corresponding underlying vprintf version:
void error(const char * fmt, ...)
{
do_stuff();
va_list ap;
va_start(ap, fmt);
vfprintf(stderr, fmt, ap);
va_end(ap);
}
Of course following the same rules you should write a verror function first and make that one call vprintf:
void verror(const har * fmt, va_list ap)
{
do_stuff();
vfprintf(stderr, fmt, ap);
}
If I understand your question properly, what you're looking for is information on variable arguments or a Variadic Function. Under C you will want to research the 'stdargs.h' header and associated manual page. Here is a simple example that takes an arbitrary number of integers and returns the average.
#include <stdarg.h>
float average(int v, ...)
{
va_list args;
int i = 0;
int num = 0;
va_start(args, v);
for (; v; v--){
i += va_arg(args, int);
num++;
}
va_end(args);
return (float)i/num;
}
See stdarg.h for dealing with functions with variable arguments.
For the specific case of simply passing the variable number of arguments to fprintf, there is vfprintf for that, e.g.,
void error (const char *fmt, ...) {
va_list args;
va_start(args, fmt);
vfprintf(stderr, fmt, args);
va_end(args);
}
For such a simple case you may also consider variadic macros (introduced in C99), e.g.,
#define error(fmt, ...) fprintf(stderr, "Error: " fmt, __VA_ARGS__)

Function arguments like printf in C

I want to implement a function Myprintf() that takes arguments like printf().
Now I am doing this by:
sprintf(demoString, "Num=%d String=%s", num, str);
Myprintf(demoString);
I want to replace this function call as:
Myprintf("Num=%d String=%s", num, str);
How is this possible?
#include <stdio.h>
#include <stdarg.h>
extern int Myprintf(const char *fmt, ...);
int Myprintf(const char *fmt, ...)
{
char buffer[4096];
va_list args;
va_start(args, fmt);
int rc = vsnprintf(buffer, sizeof(buffer), fmt, args);
va_end(args);
...print the formatted buffer...
return rc;
}
It isn't clear from your question exactly how the output is done; your existing Myprintf() presumably outputs it somewhere, maybe with fprintf(). If that's the case, you might write instead:
int Myprintf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
int rc = vfprintf(debug_fp, fmt, args);
va_end(args);
return rc;
}
If you don't want to use the return value, declare the function as void and don't bother with the variable rc.
This is a fairly common pattern for 'printf() cover functions'.
You need to define a function with variable arguments, and use vsprintf to build the string.
The printf and its relatives are in a family of functions called variadic functions and there are macros/functions in the <stddef.h> header in the C standard library to manipulate variadic argument lists. Look at the GNU docs for examples: How Variadic Functions are Defined and Used.

Resources