I want to write a C function, which can take any number of arguments and print value of int arguments only. I saw va_list and va_arg in stdarg.h, but I couldn't find any mechanism to get the number of arguments. I cannot take first argument as the number of arguments.
There's no portable way in standard C to get the number of arguments in variable argument functions.
The common way to solve it is to use the rightmost parameter parmN to provide the number of integers explicitly. For instance, your function prototype may look like this:
int foo(int number, ...);
But this is not an option to you according to your question.
Reference: C FAQ: How can I discover how many arguments a function was actually called with?
There is no (portable) way to get the number of arguments in a variadic function at runtime. That number is lost at runtime (only the compiler knows it).
Notice that on common processors and application binary interfaces (ABI) convention (e.g. x86-64 ABI on Linux), the machine itself does not know at runtime the arity of the current call in C; this is also true for others x86 calling conventions. However, when the compiler is compiling a variadic call, it does know the arity at compile time (but does not emit it in the object file).
You could define the convention that your variadic function takes as first argument the number of remaining (variadic) arguments:
void print_integers (int nbints, ...);
Then you would implement it e.g.
#include <stdio.h>
#include <stdarg.h>
void print_integers (int nbints, ...)
{
va_list args;
va_start (nbints, args);
for (int ix=0; ix<nbints; ix++) {
int curarg = va_arg(args, int);
printf(" %d", curarg);
};
va_end(args);
fflush(NULL);
}
If you cannot do this, you have to customize your preprocessor or your compiler. Perhaps a job for your MELT extension (MELT is a domain specific language to extend GCC). Or perhaps use GPP as your preprocessor.
You could also play some cpp preprocessor tricks, notably stringification and concatenation and variadic macros. For instance, you might define
void print_integers_str(const char*, ...);
#define print_my_integers(...) \
print_integers_str(#__VA_ARGS__, ##__VA_ARGS__);
Then print_my_integers(x,y) gets expanded to print_integers_str("x,y", x,y) and your varadic function print_integer_str could parse the "x,y" literal string (at least count commas). But with print_my_integers(f(x,y),g(y)+/*,,*/k)you may get a nightmare.
To be short: I recommend give up that goal and do things otherwise.
Using NARGS macro (in this case limited to 8 args):
#include <stdio.h>
#include <stdarg.h>
#define NARGS_SEQ(_1,_2,_3,_4,_5,_6,_7,_8,N,...) N
#define NARGS(...) NARGS_SEQ(__VA_ARGS__, 8, 7, 6, 5, 4, 3, 2, 1)
#define fn(...) fn(NARGS(__VA_ARGS__), __VA_ARGS__)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
for (i = 0; i < n; i++) {
printf("%d\n", va_arg(args, int));
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}
Or you can loop until -1:
#include <stdio.h>
#include <stdarg.h>
#define fn(...) fn(0, __VA_ARGS__, -1)
static void (fn)(int n, ...)
{
va_list args;
int i;
va_start(args, n);
while (1) {
i = va_arg(args, int);
if (i == -1) break;
printf("%d\n", i);
}
va_end(args);
}
int main(void)
{
fn(6, 7, 8);
return 0;
}
Related
I see this link Passing variable arguments to another function that accepts a variable argument list. What is the syntax to pass it to a macro as well?
#include <stdarg.h>
#define exampleW(int b, args...) function2(b, va_args)
static void exampleV(int b, va_list args);
void exampleB(int b, ...)
{
va_list args;
va_start(args, b);
exampleV(b, args);
//also pass args to a macro which takes multiple args after this step
??? [Is it exampleW(b, ##args)]
va_end(args);
}
static void exampleV(int b, va_list args)
{
...whatever you planned to have exampleB do...
...except it calls neither va_start nor va_end...
}
This is not possible. Macros are expanded at compile time, and so their arguments need to be known at compile time, at the point where the macro is used. The arguments to your function exampleB are in general not known until run time. And even though in many cases the arguments may be known when the call to the function is compiled, that may be in a different source file, which does not help you with macros in this source file.
You'll need to either:
have exampleB instead call a function like vfunction2 which is function2 rewritten to take a va_list parameter
reimplement exampleB as a macro
if there are a finite number of possible combinations of arguments to exampleB, then write code to handle all the cases separately:
if (b == TWO_INTS) {
int i1 = va_arg(args, int);
int i2 = va_arg(args, int);
exampleW(i1, i2);
} else if (b == STRING_AND_DOUBLE) {
char *s = va_arg(args, char *);
double d = va_arg(args, double);
exampleW(s,d);
} else // ...
do something non-portable to call the function function2 with the same arguments as were passed to exampleB, e.g. with assembly language tricks, or gcc's __builtin_apply().
This question already has answers here:
In C, given a variable list of arguments, how to build a function call using them?
(4 answers)
Closed 4 years ago.
I'm trying to call a C function that takes variadic arguments, and I need to pass in a dynamic number of arguments to the function. Additionally, this is an API I can't modify without going to a lot of effort, so if there's any possible to make this work I'll take it.
As far as I can tell, va_list is not sufficient for this purpose since you can't pass a va_list where ... was written in the original function signature.
Answers for other questions like this one talk about how to pass a ... from one function to another, but that's not what I'm doing. I need to actually dynamically generate the list of arguments, I'm not getting it in as a .... Also, all the answers I can find rely being able to modify the function to take a va_list, which is not an option here.
There was also this question, which was marked as a dupe of the previous question despite not actually asking the same question. Again, the only answer suggests converting the call to use va_list which is not an option.
I would understand if the standard didn't include a way to do this, but this seems like a case where I can imagine a perfectly reasonable implementation. This isn't so different from, say, alloca. Anyway, if it's not possible, that's fine, but I'd like the SO community to realize that this isn't a dupe of this question and deserves a definitive answer.
The API I'm calling is in C, but if there's a way to do this in C++ I would consider it.
Edit: If you have these requirements, it looks like this answer using libffi is the best way to go. There does not appear to be a way to do this either in standard C or with GCC extensions otherwise.
If you use gcc compiler, you can use __builtin_va_arg_pack() or __builtin_apply(), see here.
Examples:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
int my_printf(const char *fmt, ...)
{
void *args = __builtin_apply_args();
void *ret = __builtin_apply((void(*)())printf, args, 100);
__builtin_return(ret);
}
extern int my2_printf(const char *, ...);
extern inline __attribute__((__always_inline__,__gnu_inline__))
int my2_printf(const char *fmt, ...) {
return printf(fmt, __builtin_va_arg_pack());
}
int main()
{
my_printf("%s %s %s %s %s\n", "Hi", "I", "am", "kamil", "!");
my2_printf("%s %s %s %s\n", "Variadic", "args", "are", "fun");
return 0;
}
#edit:
As the question is also about on how to construct a dynamic argument list and then pass it to function. You can create a function for each case you need to support and use a big switch to differentiate between them.
A example for printing an array of unknown compile size:
#include <stdio.h>
#include <stddef.h>
#include <stdarg.h>
#include <stdlib.h>
#include <boost/preprocessor/repetition/repeat.hpp>
void print_array(size_t cnt, ...)
{
va_list va;
va_start(va, cnt);
printf("%s cnt=%d :", __func__, cnt);
for (size_t i = 0; i < cnt; ++i) {
printf(" %d", va_arg(va, int));
}
va_end(va);
printf("%s\n");
}
// we support an array up to that many arguments
#define CALL_PRINT_ARRAY_MAX 128
#define CALL_PRINT_ARRAY_ARGS(z, n, text) \
, arr[n]
#define CALL_PRINT_ARRAY_DECLARE(z, n, text) \
void call_print_array_##n (int arr[]) \
{ \
print_array(n BOOST_PP_REPEAT(n, CALL_PRINT_ARRAY_ARGS, ())); \
}
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_DECLARE, ())
#undef CALL_PRINT_ARRAY_DECLARE
#undef CALL_PRINT_ARRAY_ARGS
int call_print_array(int arr[], size_t n)
{
switch(n) {
#define CALL_PRINT_ARRAY_CASE(z, n, text) \
case n: call_print_array_##n(arr); break;
BOOST_PP_REPEAT(CALL_PRINT_ARRAY_MAX, CALL_PRINT_ARRAY_CASE, ())
#undef CALL_PRINT_ARRAY_CASE
default:
fprintf(stderr, "Array size is too big for what we're prepared\n");
return -1;
}
return 0;
}
int main()
{
//int a1[5] = {1,2,3,4,5};
//call_print_array(a1, sizeof(a1)/sizeof(a1[0]));
size_t size;
scanf("%zu", &size); // insecure
int * a2 = calloc(size, sizeof(*a2));
for (size_t i = 0; i < size; ++i)
a2[i] = i;
call_print_array(a2, size);
return 0;
}
The easiest way to do this would be with variadic macros, kind of like the way it's done for eprintf:
#define eprintf(…) fprintf (stderr, __VA_ARGS__)
__VA_ARGS__ expands into the full argument list passed into the macro with which you can then call the other function declared with .... Unfortunately what you want to do cannot be done within a function without going through a lot of effort that you seem to want to avoid.
When learning C I see that printf can receive many arguments as it is passed.
And I don't know how C can implement a function like this, where the user can type as many parameters as the user wants. I have thought about pointers, too but still have no bright idea. If anyone has any ideas about this type of function, please tell me.
You need to use va_args, va_list and the like.
Have a look at this tutorial.
http://www.cprogramming.com/tutorial/c/lesson17.html
That should be helpful.
You have to use the ... notation in your function declaration as the last argument.
Please see this tutorial to learn more: http://www.cprogramming.com/tutorial/c/lesson17.html
#include <stdarg.h>
#include <stdio.h>
int add_all(int num,...)
{
va_list args;
int sum = 0;
va_start(args,num);
int x = 0;
for(x = 0; x < num;x++)
sum += va_arg(args,int);
va_end(args);
return sum;
}
int main()
{
printf("Added 2 + 5 + 3: %d\n",add_all(3,2,5,3));
}
You use C varargs to write a variadic function. You'll need to include stdargs.h, which gives you macros for iterating over an argument list of unknown size: va_start, va_arg, and va_end, using a datatype: va_list.
Here's a mostly useless function that prints out it's variable length argument list:
void printArgs(const char *arg1, ...)
{
va_list args;
char *str;
if (arg1) We
va_start(args, arg1);
printf("%s ", arg1);
while ((str = va_arg(argp, char *)) != NULL)
printf("%s ", str);
va_end(args);
}
}
...
printArgs("print", "any", "number", "of", "arguments");
Here's a more interesting example that demonstrates that you can iterate over the argument list more than once.
Note that there are type safety issues using this feature; the wiki article addresses some of this.
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
I have zillions of my_printf() function calls in a huge program. I now want to convert them all so that the function takes a new integer argument (call it x) without having to edit the zillions of calls. If my_printf only ever took exactly one string argument then I could do something like this:
#define my_printf(str) _my_printf(x,str)
void _my_printf(int x,char *str) // changed from my_printf(char *str)
{
// stuff
}
But as my_printf takes a variable number of arguments I'm not sure how to do it. Can it be done?
EDIT: for those wondering why I should want to do such a thing, here's a related example:
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
#define function(x) _function(__FILE__,__LINE__,x)
#else // speed critical optimised mode
#define function(x) _function(x)
#endif
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
void _function(char *file,int line,int x)
#else
void _function(int x)
#endif
{
// stuff
#if BELT_AND_BRACES_DIAGNOSTIC_MODE
if (something_went_wrong)
{
printf("Cock up in function when called from %s line %d\n",file,line);
}
#endif
}
You may use C99 variadic macros:
#define my_printf(...) my_printf_(x, __VA_ARGS__)
As Microsoft's implementation suppresse trailing commas, the str argument can be added explicitly
#define my_printf(str, ...) my_printf_(x, str, __VA_ARGS__)
but this would lead to a syntax error in standard C when invoked without variadic arguments
my_printf("foo")
or an empty argument list
my_printf("foo",)
Therefore, I'd go with the first version.
If the code can be compiled as C99 code, you can define a variadic macro
#define my_printf(str, args...) _my_printf(x, str, ##__VA_ARGS__)
The preprocessor will replace the arguments ... and the GNU preprocessor will remove the trailing comma in case the macro is invoked only with the str argument.
The best thing is of course to bite the bullet and edit the code. Otherwise you're creating a "mystery", that needs to be solved by all future maintainers of the code. Even if that's only you, this is exactly the kind of clever trick that you will forget all about. It sucks to come back, and be puzzled by strange pointless-seeming macros.
That said, if you're using a GNU toolchain, you can perhaps look into using varargs macros.
Not with standard C89 macros, you can't. However you can get the same effect using functions, by breaking out the main part of your my_printf function into a vmy_printf function, analagous to the standard vprintf:
#include <stdarg.h>
int vmy_printf(int x, const char *format, va_list ap)
{
/* main body of my_printf goes here, taking its varargs from ap */
}
/* new_my_printf(), for callers who know about the x parameter */
int new_my_printf(int x, const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(x, format, ap);
va_end(ap);
return n;
}
/* my_printf(), for the old callers who don't know about x */
int my_printf(const char *format, ...)
{
int n;
va_list ap;
va_start(ap, format);
n = vmy_printf(DEFAULT_X, format, ap);
va_end(ap);
return n;
}
(This kind of thing is why those v... versions of all the standard varargs functions exist.)
If my_printf already takes a variable number of arguments, I'm not sure why you need to wrap 'one more argument' in a macro... Just insert the new calls with the extra argument and be done with it; the old calls should still work as expected.
A simple solution to this problem is...
#define my_printf(x) printf x
(note the missing braces)
To call it, use:
my_printf((any number of arguments))
(note the double braces)