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__)
Related
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("");
}
I'm trying to pass __ VA_ARGS __ to a function. For some reason the first argument is always wrong (seems like an address):
#define PRINTF_ERROR(format, ...) {\
PrintfError(format, __FUNCTION__, ##__VA_ARGS__);\
}
void PrintfError(const char* format, const char* function, ...)
{
va_list args;
va_start(args, format);
printf("%s(): ", function);
printf(format, args);
va_end(args);
}
For example, when trying to print the same variable:
"A = 0x20005524 A = 0x00000007"
Does anybody know why?
Thanks
There are two problem here.
First, va_start expects the last named parameter of the current function as its second parameter. In this case that would be function.
The second issue is that you're passing a va_list into printf. You should be calling vprintf instead.
void PrintfError(const char* format, const char* function, ...)
{
va_list args;
va_start(args, function); // pass "function" instead of "format"
printf("%s(): ", function);
vprintf(format, args); // call vprintf
va_end(args);
}
You've got the order of your parameters wrong. The one you pass to va_start() has to be the one before the ... because it's used to work out where the extra arguments start
So your function should look like this...
void PrintfError(const char* function, const char* format, ...)
{
va_list args;
va_start(args, format);
From man va_start:
void va_start(va_list ap, last);
[...]
DESCRIPTION
va_start()
[...]
The argument last is the name of the last argument before the variable argument list, that is, the last argument of which the calling function knows the type.
So given
void PrintfError(const char* format, const char* function, ...)
just change
va_start(args, format);
to be
va_start(args, function);
Also this
printf(format, args);
(which probably is a typo) should be
vprintf(format, args);
Unrelated to your question, here
#define PRINTF_ERROR(format, ...) {\
PrintfError(format, __FUNCTION__, ##__VA_ARGS__);\
}
the curly braces are only half the way to make this safe.
Better do
#define PRINTF_ERROR(format, ...) do {\
PrintfError(format, __FUNCTION__, __VA_ARGS__);\
} while (0)
Also no need for the ##.
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.
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.
I want to pass a va_list through to another function. Here is an example of what i am trying to do:
void my_printf_1(char* string, ...) {
va_list ap;
va_start(ap, string);
printf(string, ap);
va_end(ap);
}
void my_printf_2(char* string, ...) {
va_list ap;
va_start(ap, string);
printf(string, *ap);
va_end(ap);
}
int main(void) {
my_printf_1("Hello %i\n", 12); //Shows me the pointer
my_printf_1("Hello \n"); //Runtime Error - too many arguments
my_printf_2("Hello %i\n", 12); //Displays correctly because 12 < char
my_printf_2("Hello %i\n", 500); //Displays incorrectly because 500 > char
my_printf_2("Hello %i %i\n", 12, 12); //Displays 12, then crashes Runtime Error not enough arguments
my_printf_2("Hello \n"); //Runtime Error - too Many Arguments
}
It seems to me that my va_list ap is a char pointer, how can i get the whole List? How can i rewrite my_printf() to pass the whole or a fake va_list to subfunctions? I can not modify my subfunctions to accept va_list pointers, so i will have to modify my_printf.
EDIT:
I realize that the following would work, however this is not what i want.
void my_printf_1(char* string, ...) {
va_list ap;
va_start (ap, string);
vprintf(string, ap);
va_end(ap);
}
You need to do what you say, but explicitly. That is, pass the actual va_list object.
See the vsnprintf() function for inspiration. Functions that take an explicit va_list are often prefixed with a v in the standard library.
The va_list doesn't have an internal structure that you can work with, it's opaque. All you can do is defined in the <stdarg.h> header.
Check out vprintf and friends. http://www.manpagez.com/man/3/vprintf/