1

I have the following function that accepts a varying number of integer parameters and returns the sum.

int sum(int a, ...){
    va_list nums;
    va_start(nums, a);
    int res=0;
    for(int i=0; i<a; i++) {
        res += va_arg(nums, int);
    }
    va_end(nums);
    return res;
}

I need to pass each value of the array as a parameter to the function rather than passing the array itself. The array can be of varying length leading to a varying length of arguments to pass too.

printf("The sum is: %d", sum(size, args[0], args[1], ```need all elements of args[] array here```));

To put forth some perspective, I'm using this sum function to understand how I can go about doing this. It would be helpful to know how to achieve this in a more general setting rather than this exact function.

Please let me know if you need any more information.

Please do look at this question, which is similar, however, I require a solution in C.

sighclone
  • 102
  • 1
  • 10
  • 2
    Why on earth would you do it that way? `int sum(size_t n, int arr[n])` would be a sane signature for the function — there are alternative notations, but the idea is the same. With the variable argument list function, you can use `sum(4, a[0], b[1], c[2], d[4])` if you have four appropriately sized arrays. The number of arguments is fixed at compile time — unlike the array-based alternative. – Jonathan Leffler Feb 16 '23 at 06:01
  • Does https://stackoverflow.com/questions/50957748/passing-a-dynamic-set-of-variadic-arguments-to-a-c-function and https://stackoverflow.com/questions/12263745/in-c-given-a-variable-list-of-arguments-how-to-build-a-function-call-using-the answer your question? – KamilCuk Feb 16 '23 at 07:59
  • @JonathanLeffler Yes, I could just pass the array itself. However, I'm only using this sum() function as an example for myself to understand how I can go about doing this in another function. I'll update the question to include more perspective. I cannot use `sum(4, a[0], b[1], c[2], d[4])` because the number of arguments is unknown at runtime. – sighclone Feb 16 '23 at 08:17
  • .....yes, which is why you pass the array and length/index/whatever. – Martin James Feb 16 '23 at 09:21
  • @KamilCuk Although the [first answer](https://stackoverflow.com/questions/50957748/passing-a-dynamic-set-of-variadic-arguments-to-a-c-function) is on the same page, as I've said, I was hoping there was a way of achieving this without changing the function itself, but as pointed out by some of the answers, this is not possible. – sighclone Feb 18 '23 at 17:09

2 Answers2

3

The short answer is that there's no way to do exactly this in the C language. There is no ES6-like spread operator in C, nor similar functionality. I don't think there's any particular reason why they couldn't (you would just have to push more arguments onto the stack); they just never made one.

However, there are various other things you can do:

  • If variadic arguments were already passed into the function calling your function, you can pass along the va_list to a function declared to take a va_list. See Passing variable arguments to another function that accepts a variable argument list

  • As @JonathanLeffer suggests, the most natural way to write this code in C is by constructing an array of what "would be" your variadic arguments, and passing that into a function that expects an array (well, technically, a pointer, because arrays decay to pointers). For example:

    int sum_array(int a, int nums[]){
      int res=0;
      for(int i=0; i<a; i++) {
        res += nums[i];
      }
      return res;
    }
    
    • In certain circumstances, it may be more convenient for a function like sum_array to take only the nums array/pointer, which would itself indicate the end of the array with a 0 or -1 value in the last slot. This is just another convention for indicating the end, which the caller has to set up.
  • You could then, if you really wanted to, write a variadic function that collects its arguments into an array and calls sum_array, if you want a variadic version as well. (Of course, you could also just implement the variadic and array versions separately, but for nontrivial functions it may be a pain to implement them twice.)

    int sum_variadic(int a, ...){
      va_list nums;
      va_start(nums, a);
      int arr[a];
      for(int i=0; i<a; i++) {
        arr[i] = va_arg(nums, int);
      }
      va_end(nums);
      return sum_array(a, arr);
    }
    
  • you could also use a variadic macro for the same purpose:

    #define sum_macro(size, ...) sum_array(size, (int[]){__VA_ARGS__})
    

In summary: going from variadic to array in C is trivial, going from array to variadic is impossible.

You can also use extensions to the C language to do it anyway, as described in Passing a dynamic set of variadic arguments to a C function and In C, given a variable list of arguments, how to build a function call using them?, which @KamilCuk linked to.

1

You can avoid passing the number of arguments explicitly by using a variadic macro that constructs a compound literal array instead of a vararg function:

#include <stdio.h>

#define sum_int(...)  (sum_int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int), (int[]){__VA_ARGS__})

int (sum_int)(size_t count, const int *a) {
    int sum = 0;
    for (size_t i = 0; i < count; i++) {
        sum += a[i];
    }
    return sum;
}

int main() {
    printf("sum = %d\n", sum_int(1, 2, 3));
    return 0;
}

This approach can be used for any purpose, as long as the types of the variable arguments are converted implicitly to the array type.

If you want to pass just the arguments to your sum function without changing its definition, you can use a variation of the macro:

#include <stdio.h>

int sum(int a, ...) {
    va_list nums;
    va_start(nums, a);
    int res = 0;
    for (int i = 0; i < a; i++) {
        res += va_arg(nums, int);
    }
    va_end(nums);
    return res;
}

#define sum(...)  (sum)((int)(sizeof((int[]){__VA_ARGS__}) / sizeof(int)), __VA_ARGS__)

int main() {
    printf("sum = %d\n", sum(1, 2, 3));
    return 0;
}

Note however that there is no type checking with this approach and sum(1, 2.0, 3) would have undefined behavior.

chqrlie
  • 131,814
  • 10
  • 121
  • 189