How to find out the last argument of va_list?

I am reading about how to pass optional arguments to a function. But I can’t understand it. When I see examples, they are confusing and a bit complicated. Therefore, I just started with a very simple program with what I understood so far.

The program below just prints the variables.

void print(int x, ...) { va_list ap; int i = 4; // I know I'm passing only 4 opt variables. int num; va_start(ap, x); while(i--) { // How to know how many variables came in real time? num = va_arg(ap, int); printf("%d\n", num); } va_end(ap); return; } int main() { print(1,2,3,4,5); return 0; } 

I do not know if the program is correct or not. But it does work. When I change the value of i to 5 print trash. How do I know how many arguments I received (e.g. argc in main )?

+6
source share
3 answers

You can see the NARGS macro

Adapted to your code:

 #include <stdio.h> #include <stdarg.h> #define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,_9,N,...) N #define NARGS(...) NARGS_SEQ(__VA_ARGS__, 9, 8, 7, 6, 5, 4, 3, 2, 1) #define print(...) fnprint(NARGS(__VA_ARGS__), __VA_ARGS__) void fnprint(int n, ...) { va_list ap; int num; va_start(ap, n); while (n--) { num = va_arg(ap, int); printf("%d\n", num); } va_end(ap); return; } int main(void) { print(1, 2, 3, 4, 5); return 0; } 

EDIT: If you want to use the same name for a macro and a function, use () to stop the preprocessor from expanding the function definition:

 #define print(...) print(NARGS(__VA_ARGS__), __VA_ARGS__) void (print)(int n, ...) /* Note () around the function name */ { ... 

EDIT 2: Another (ugly) method (but without limiting the number of arguments) using compound literals (std 99) and sizeof :

 #include <stdio.h> #include <stdarg.h> #define print(...) print(sizeof((int []) {__VA_ARGS__}) / sizeof(int), __VA_ARGS__) void (print)(int n, ...) { va_list ap; int num; va_start(ap, n); while (n--) { num = va_arg(ap, int); printf("%d\n", num); } va_end(ap); return; } int main(void) { print(1, 2, 3, 4, 5); return 0; } 

print expands to:

 print(sizeof((int []) {1, 2, 3, 4, 5}) / sizeof(int), 1, 2, 3, 4, 5); 

But constructions of type print(1, 2, 3, a_var++, 4, 5); or print(1, 2, some_func_returning_int(), 4, 5); evaluate a_var++ and some_func_returning_int() twice, this is a big problem.

+7
source

There is no way to know how many arguments are passed from within the function to the variable arguments, so functions like printf use special format strings that tell the function how many arguments to expect.

Another way, of course, is to pass the number of “extra” arguments as the first argument, for example

 print(4, 1, 2, 3, 4); 

Or have a special value that cannot be in the list as the last argument, for example

 print(1, 2, 3, 4, -1); 

You should also note that the last non-va argument that you pass to the function (an argument named num in your case) is not included in va_list , so in your case with the code shown with 4 as a hard-coded number of arguments, you are all you will print garbage as well, because you pass 1 for the num argument, and then the three va_list arguments.

Also note, because you are using num as an argument, and as the name of a local variable.

+8
source

Another ugly way for int and strings:

 #include <stdio.h> #include <stdarg.h> #define print(...) fnprint("{" # __VA_ARGS__ ) fnprint(char *b) { int count = 0, i; if (b[1] != '\0') { for (i =2; b[i]; i++) { if (b[i] == ',') count++; } count++; } printf("\ncount is %i\n", count); } int main(void) { print(); print("1", "2"); print(1, 2, 3, 4, 5); return 0; } 
0
source

All Articles