How to print values of variable arguments in C? - c

I have a function
void func(int x, char *str, ...)
{
...
}
I am invoking it as follows:
func(1, "1", "2", "3");
How can I print the values of all the extra arguments (2, 3) in function?

From the man page of STDARG about the use of va_arg to get the next argument:
If there is no next argument, or
if type is not compatible with the
type of the actual next argument (as
promoted according to the default
argument promotions), random errors
will occur.
Hence, unless you want random errors to creep in, you should know the number of arguments beforehand.
Even so, if you want to throw caution to the winds, you could try:
void func(int x,char *str, ...)
{
va_list al;
va_start(al,str);
while(x>0)
{
str=va_arg(al,char *);
--x;
}
while(str != NULL)
{
printf("%s ",str);
str=va_arg(al,char *);
}
va_end(al);
}
With,
func(1,"1","2","3");
I got the output,
2 3 U��WVS�O
If it satisfies your purpose, you could pick out the required number of arguments from this output.

It is customary with variable arguments to pass a string which describes the variable arguments, e.g. printf( char *format_string, ... );
This is a solution - and the customary solution - to your problem.
Pass an additional argument which describes the variable arguments, and then use that information to process the variable arguments.
So, if you receive a printf-like format string and it is "%d%u", you know you have an int, followed by an unsigned int.

lookup va_list in this site. Example: What is ellipsis operator in c

Related

va_list in C: Creating a function that doesn't need a argument count like 'printf'

Using the <stdarg.h> header, one can make a function that has a variable number of arguments, but:
To start using a va_list, you need to use a va_start macro that needs to know how many arguments there, but the printf & ... that are using va_list don't need the argument count. How can I create a function that doesn't need the argument count like printf?
Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list? (so in pseudocode, it would be like void printfRipOff(const char* format, ...) {printf(format, ...);})
Let's say I want to create a function that takes a va_list and instead of using it, passes it to another function that requires a va_list?
Look at function vprintf( const char * format, va_list arg ); for one example of a function that takes a va_list as an input parameter.
It is basically used this way:
#include <stdio.h>
#include <stdarg.h>
void CountingPrintf(const char* format, ...)
{
static int counter = 1;
printf("Line # %d: ", counter++); // Print a Counter up front
va_list args;
va_start(args, format); // Get the args
vprintf(format, args); // Pass the "args" through to another printf function.
va_end(args);
}
int main(void) {
CountingPrintf("%s %s\n", "Hello", "World");
CountingPrintf("%d + %d == %d\n", 2, 3, 2+3);
return 0;
}
Output:
Line # 1: Hello World
Line # 2: 2 + 3 == 5
Functions like printf() and scanf() have the format string argument that tells them the number and types of the arguments that must have been provided by the function call.
If you're writing your own function, you must have some way of knowing how many arguments were provided and their types. It may be that they are all the same type. It may be that they're all pointers and you can use a null pointer to indicate the end of the arguments. Otherwise, you probably have to include a count.
You can do that as long as provided the called function expects a va_list. There are caveats (see C11 §7.16 Variable arguments) but they're manageable with a little effort.
A very common idiom is that you have a function int sometask(const char *fmt, ...) and a second function int vsometask(const char *fmt, va_list args), and you implement the first as a simple call to the second:
int sometask(const char *fmt, ...)
{
va_list args;
va_start(fmt, args);
int rc = vsometask(fmt, args);
va_end(args);
return rc;
}
The second function does the real work, of course, or calls on other functions to do the real work.
In the question, you say:
… va_start macro that needs to know how many arguments …
No; the va_start macro only needs to know which argument is the one before the ellipsis — the argument name before the , ... in the function definition.
In a comment, you say:
This is what I'm trying to write, but it didn't work.
string format(const char* text, ...)
{
// temporary string used for formatting
string formattedString;
initializeString(&formattedString, text);
// start the va_list
va_list args;
va_start(text, args);
// format
sprintf(formattedString.array, text, args);
// end the va_list
va_end(args);
return formattedString;
}
As noted by abelenky in a comment, you need to use vsprintf():
string format(const char* text, ...)
{
string formattedString;
initializeString(&formattedString, text);
va_list args;
va_start(text, args);
vsprintf(formattedString.array, text, args);
va_end(args);
return formattedString;
}
That assumes that the formattedString has enough space in the array for the formatted result. It isn't immediately obvious how that's organized, but presumably you know how it works and it works safely. Consider using vsnprintf() if you can determine the space available in the formattedString.
The printf and scanf family of functions don't need to be explicitly passed the length of the va_list because they are able to infer the number of arguments by the format string.
For instance, in a call like:
printf("%d %c %s\n", num, c, "Hello");
printf is able to examine the first parameter, the format string, and see that it contains a %d, a %c, and a %s in that order, so it can assume that there are three additional arguments, the first of which is a signed int, the second is a char and the third is a char* that it may assume is a pointer to a null-terminated string.
To write a similar function that does not need to be explicitly told how many arguments are being passed, you must find a way to subtly give it some information allowing it to infer the number and types of the arguments in va_list.

How do I print function parameters in C?

I know this question has been asked many times but sorry, I couldn't find the answer. Below is a function with parameters (how many parameters is unknown). How do I get all parameters and then print them?
int func(int a, int b, ...) {
// print the parameters
}
The short answer is "you don't." C doesn't give you any mechanism to know when the arguments end.
If you want to use varargs, you will need to give yourself a mechanism that will tell you how many arguments there are, and how big each one is. To take the most well-known example, printf() requires its first argument to be a formatting string, that tells it about the varargs and their sizes.
If you know that all your arguments are going to be the same size (say, ints), you can design your routine so the first argument is the number of arguments, something like:
void
my_func (int n_args, ...)
{
va_list ap;
int i;
va_start(ap, n_args);
for (i = 0 ; i < n_args ; i++) {
process(va_arg(ap, int));
}
va_end(ap);
}

Writing a loud failing scanf: which is the type signature?

I decided to write a variation of the scan C function that instead of returning an int stating success or failure would print an error message and abort the program on error.
void aborting_scanf(const char *format, ???) {
if (scanf(format, &var) != 1)
puts("Invalid input");
exit(1);
}
The problem is what to write instead of the ???, in the man page, the type signature is:
int scanf(const char *format, ...)
But then how can I name the target variable?
In theory I could write a version for each type by hand but it would incredibly repetitive so I am looking for a more general solution to avoid code duplication.
You need to use variable arguments for this along with vscanf:
void aborting_scanf(const char *format, ...) {
va_list ap;
va_start(ap, format);
if (vscanf(format, ap) != 1) {
puts("Invalid input");
exit(1);
}
va_end(ap);
}
The ... argument tells the compiler that the remaining arguments are of varying types and numbers and can be anything. The variable of type va_list allows you to access these values, and the vscanf function can read this directly.
scanf uses a variable argument list as indicated by the ... parameter. You manipulate these with the functions in stdarg.h. This format is not suitable to give a full introduction into variable argument lists, read a tutorial/book of choice about it.

How to allow variable parameters passed to function

I have a function that accepts 3 parameters, however I also want it to only accept the first two and not care about the third. How can I do this in C. I tried just declaring the function in the header file as void list()
thinking this might imply that we don't care how many parameters but this didn't work.
void list(uint8_t _pin, unsigned int time, unsigned long tasks)
What you want is called Variadic function. It can accept variable number of arguments.
**Famous examples: printf()/scanf()
These functions contain an ellipsis (…) notation in the argument list, and uses special macros to access the variable arguments.
The most basic idea is to write a function that accepts a variable number of arguments. So, it must be declared with a prototype that says so.
The syntax of ISO C requires at least one fixed argument before the …. thus, we write the fixed arguments as usual, and then add the … notain at the end of the parameter list to indicate the possibility of additional arguments. For example,
int func (const char *a, int b, …)
{
…
}
defines a function func() which returns an int and takes two required arguments, a const char * and an int. These are followed by any number of anonymous arguments.
You can check the On-line GNU manual for more details.
Here is a trick explained in SO here : C default arguments.
You can make third parameter as default in function declaration as follows:
typedef struct {
uint8_t _pin;
unsigned int time;
unsigned long tasks;
} f_args;
double var_f(f_args in){
uint8_t _pin = in._pin? in._pin : 8;
unsigned int time = in.time ? in.time : 3;
unsigned long tasks =in.tasks? in.taska : 0;
return f_base(i_out, x_out);
return list(_pin, time, tasks);
}
#define list(...) var_f((f_args){__VA_ARGS__});
So you can call your function as follows:
list(2,5);
A different solution to your problem without variable parameters is to do something like this:
void list(int argc, char **argv);
You have two parameters always, however what changes is the contents of argv and the count of what is inside it. You might have seen this in the entry point (main function) of other C programs. The parameters argc, argument count, and argv, argument vector, give the number and values of what you need.
Then inside list you could do something like:
if (argc == 2)
do_something;
else if(argc == 3)
do_something_else;
else
whatever;

Do C functions support an arbitrary number of arguments?

PHP has a func_get_args() for getting all function arguments, and JavaScript has the functions object.
I've written a very simple max() in C
int max(int a, int b) {
if (a > b) {
return a;
} else {
return b;
}
}
I'm pretty sure in most languages you can supply any number of arguments to their max() (or equivalent) built in. Can you do this in C?
I thought this question may have been what I wanted, but I don't think it is.
Please keep in mind I'm still learning too. :)
Many thanks.
You could write a variable-arguments function that takes the number of arguments, for example
#include <stdio.h>
#include <stdarg.h>
int sum(int numArgs, ...)
{
va_list args;
va_start(args, numArgs);
int ret = 0;
for(unsigned int i = 0; i < numArgs; ++i)
{
ret += va_arg(args, int);
}
va_end(args);
return ret;
}
int main()
{
printf("%d\n", sum(4, 1,3,3,7)); /* prints 14 */
}
The function assumes that each variable argument is an integer (see va_arg call).
Yes, C has the concept of variadic functions, which is similar to the way printf() allows a variable number of arguments.
A maximum function would look something like this:
#include <stdio.h>
#include <stdarg.h>
#include <limits.h>
static int myMax (int quant, ...) {
va_list vlst;
int i;
int num;
int max = INT_MIN;
va_start (vlst, quant);
for (i = 0; i < quant; i++) {
if (i == 0) {
max = va_arg (vlst, int);
} else {
num = va_arg (vlst, int);
if (num > max) {
max = num;
}
}
}
va_end (vlst);
return max;
}
int main (void) {
printf ("Maximum is %d\n", myMax (5, 97, 5, 22, 5, 6));
printf ("Maximum is %d\n", myMax (0));
return 0;
}
This outputs:
Maximum is 97
Maximum is -2147483648
Note the use of the quant variable. There are generally two ways to indicate the end of your arguments, either a count up front (the 5) or a sentinel value at the back.
An example of the latter would be a list of pointers, passing NULL as the last. Since this max function needs to be able to handle the entire range of integers, a sentinel solution is not viable.
The printf function uses the former approach but slightly differently. It doesn't have a specific count, rather it uses the % fields in the format string to figure out the other arguments.
In fact, this are two questions. First of all C99 only requires that a C implementation may handle at least:
127 parameters in one function
definition
127 arguments in one function call
Now, to your real question, yes there are so-called variadic functions and macros in C99. The syntax for the declaration is with ... in the argument list. The implementation of variadic functions goes with macros from the stdarg.h header file.
here is a link to site that shows an example of using varargs in c Writing a ``varargs'' Function
You can use the va_args function to retrieve the optional arguments you pass to a function. And using this you can pass 0-n optional parameters. So you can support more then 2 arguments if you choose
Another alternative is to pass in an array, like main(). for example:
int myfunc(type* argarray, int argcount);
Yes, you can declare a variadic function in C. The most commonly used one is probably printf, which has a declaration that looks like the following
int printf(const char *format, ...);
The ... is how it declares that it accepts a variable number of arguments.
To access those argument it can uses va_start, va_arg and the like which are typically macros defined in stdarg.h. See here
It is probably also worth noting that you can often "confuse" such a function. For example the following call to printf will print whatever happens to be on the top of the stack when it is called. In reality this is probably the saved stack base pointer.
printf("%d");
C can have functions receive an arbitrary number of parameters.
You already know one: printf()
printf("Hello World\n");
printf("%s\n", "Hello World");
printf("%d + %d is %d\n", 2, 2, 2+2);
There is no max function which accepts an arbitrary number of parameters, but it's a good exercise for you to write your own.
Use <stdarg.h> and the va_list, va_start, va_arg, and va_end identifiers defined in that header.
http://www.kernel.org/doc/man-pages/online/pages/man3/stdarg.3.html

Resources