Function in C with unlimited arguments? - c

I want to define a function in C language which can take an unlimited number of arguments of any datatype.
For example: printf(), scanf(), etc.
Any idea on this?

To use variable number of arguments in C you need to include the header
#include <stdarg.h>
printf() in C is an example of function that takes variable number of arguments.
int printf(const char *fmt, ...)
More info here

Declare the function as taking a ... last argument. You'll need to use the macros from <stdarg.h> to access the arguments as a va_list.
If you just want something "like printf, but with a little extra behavior", then you can pass the va_list to vprintf, vfprintf, or vsprintf.
#include <stdarg.h>
#include <stdio.h>
#include <time.h>
#ifdef __GNUC__
__attribute__((format(printf, 1, 2)))
#endif
void PrintErrorMsg(const char* fmt, ...)
{
time_t now;
char buffer[20];
va_list args;
va_start(args, fmt);
time(&now);
strftime(buffer, sizeof(buffer), "%Y-%m-%d %H:%M:%S", gmtime(&now));
fprintf(stderr, "[%s] ", buffer);
vfprintf(stderr, fmt, args);
fputc('\n', stderr);
va_end(args);
}

void printf(char* format, ...)
{
}
Look up Variadic Functions and varargs.h or stdarg.h (depending on the compiler).

See the <stdarg.h> header and related documentation.

Related

C Is it possible for a function taking va_list to use it more than once?

In the program below, the variadic function process_message passes its variable arguments via the va_list argp parameter to print_message. argp is in turn passed to vsnprintf which calculates the length of the format string.
However, if argp is passed to a another function called from within print_message such as vprintf(fmt, argp), it produces nonsense output. Is it possible for a function taking va_list parameter to use it more than once?
#include <stdio.h>
#include <stdarg.h>
void process_message(const char *fmt, ...);
void print_message(const char *fmt, va_list argp);
int main(void) {
process_message("%s:%d\n", "test message", 1);
return 0;
}
void process_message(const char *fmt, ...) {
va_list argp;
va_start(argp, fmt);
print_message(fmt, argp);
va_end(argp);
}
void print_message(const char *fmt, va_list argp) {
/*Calculate and print the length of the format string*/
int len = vsnprintf(NULL, 0, fmt, argp);
printf("Length of format string = %d\n", len);
/*Print the rendered format string - this produces a nonsense output
*if argp was aleady passed to another function earlier */
vprintf(fmt, argp);
}
You can use va_copy:
The va_copy() macro copies the (previously initialized) variable argument list src to dest. The behavior is as if va_start() were applied to dest with the same last argument, followed by the same number of va_arg() invocations that was used to reach the current state of src.
You print_message() could be:
void print_message(const char *fmt, va_list argp) {
/*Calculate and print the length of the format string*/
va_list argp_copy;
va_copy(argp_copy, argp);
int len = vsnprintf(NULL, 0, fmt, argp_copy);
va_end(argp_copy);
printf("Length of format string = %d\n", len);
/*Print the rendered format string - this produces a nonsense output
*if argp was aleady passed to another function earlier */
vprintf(fmt, argp);
}
NOTE:
Don't forget to call va_end after using a copied va_list.
C11:
Each invocation of the va_start and va_copy macros shall be matched by a corresponding invocation of the va_end macro in the same function.

First argument is wrong when passing __VA_ARGS__

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 ##.

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.

Trouble Wrapping Printf in C Program

I'm trying to wrap printf in a C program (well, actually _snprintf but this example is simpler) and am having trouble getting the variable argument stuff to work. Here is my code:
#include <stdio.h>
#include <stdarg.h>
void works(void)
{
printf("%d\n", 100);
}
void wrap_printf(const char *fmt, ...)
{
va_list args;
va_start(args, fmt);
printf(fmt, args);
va_end(args);
}
void broken(void)
{
wrap_printf("%d\n", 100);
}
int main(void)
{
works();
broken();
return 0;
}
Here is my output:
100
3668388
The args variable looks good after the call to va_start in my code, but as soon as I step into the C runtime code and they call va_start the value looks bad. Any thoughts as to what I might be doing wrong?
va_start(args, fmt);
vprintf(fmt, args);
va_end(args);
You need to call vprintf instead of printf. The v*printf functions understand va_List arguments. I'm surprised you didn't get a warning.
You're passing args which is a va_list, but printf() of course expects the arguments directly, it has no way of knowing that its second argument suddenly is a va_list.
You should be using vprintf(), the variable-argument version which does indeed expect a va_list and knows how to extract the values from it.

Resources