2

Hello i would like to pass a struct to a variadic functions and use values inside the said struct in C. What i do not know how to do is how to access the contents of each struct that is passed.

Here is a example situation

typedef struct  {
 int num;
 bool dontIncludeFlag;
} number;


int average(unsigned count, ...){
    va_list ap;
    int j;
    int sum = 0;

    va_start(ap, count); 
    for (j = 0; j < count; j++) {
        if(va_arg(ap,number.dontIncludeFlag))        //This line does not work
        sum += va_arg(ap.num, number);               //so does this line
    }
    va_end(ap);

    return sum / count;
}


int main(){

   number a,b,c;

   a.num= 5;
   a.dontIncludeFlag = 0;

   b.num= 2;
   b.dontIncludeFlag= 1;

   c.num= 1;
   c.dontIncludeFlag= 0;

   average(3,a,b,c);
}

How do i access the contents of the struct arguments i passed

Jake quin
  • 738
  • 1
  • 9
  • 25
  • 2
    There must be quite a few online-tutorials on how to use variadic function all over the Internet. All of them should point out that the `va_arg` "function" (it's really a macro) will take a *type* as argument, and it get the next *whole* argument. You can't use `va_arg` to get part of an argument (like parts of a structure). – Some programmer dude Apr 03 '21 at 15:54
  • Does this answer your question? [An example of use of varargs in C](https://stackoverflow.com/questions/15784729/an-example-of-use-of-varargs-in-c) – Nikos Athanasiou Apr 03 '21 at 16:00
  • 2
    @Someprogrammerdude you actually led me to solve the problem, sadly the one i was reading did not mention any of that. so how i solved it is inside the for loop i created a temp struct variable `number temp = va_arg(ap,number)` and from there its walk in the park , replace the two problematic line with `if(temp.dontIncludeFlag == 0)` and `sum+= temp.num;`. If you want to post an answer good sir, ill accept it so that you can take the points – Jake quin Apr 03 '21 at 16:08
  • @NikosAthanasiou actually it does not, my problem is accessing the struct that was passed inside the variadic function. Some programmer dude actually gave me the necessary information to solve the problem – Jake quin Apr 03 '21 at 16:13
  • I think that defaulting to `int` in your function when you just write `unsigned` instead of `unsigned int` might be a bit confusing to newbies. For those interested in the 'why' of this defaulting, this might be very interesting: https://forum.arduino.cc/t/unsigned-keyword-without-a-type-specifer-default-int/677391 – Paul Efford Jan 21 '23 at 06:30

3 Answers3

5

The code uses va_arg incorrectly. Use it to assign a variadic argument to a variable, and then access the member.

    number n;
    for (j = 0; j < count; j++) {
        n = va_arg(ap, number);
        if(n.dontIncludeFlag)
            sum += va_arg(ap.num, number);
    }
Samuel Hunter
  • 527
  • 2
  • 11
0

I think this is what you're looking for :

#include <stdio.h>
#include <stdarg.h>
#include <stdbool.h>

typedef struct s_number {
    int num;
    bool dontIncludeFlag;
} number_t;


float average(unsigned int count, ...)
{
    int j = 0;
    va_list ap;
    float sum = 0;
    number_t tmp;                   // This element will be our portal to access both
                                    // `.num` and `.dontIncludeFlag` properties.

    va_start(ap, count); 
    for (j = 0; j < count; j++) {
        tmp = va_arg(ap, number_t); // Pops out the element
        if (tmp.dontIncludeFlag)    // Now able to access to the .dontIncludeFlag property
            sum += tmp.num;         // Now able to access to the .num property
    }
    va_end(ap);
    return sum / count;
}

int main(void)
{
    number_t a = { .num = 5, .dontIncludeFlag = 0 };
    number_t b = { .num = 2, .dontIncludeFlag = 1 };
    number_t c = { .num = 1, .dontIncludeFlag = 0 };
    float result = average(3, a, b, c);

    printf("Average : %f\n", result);
    return 0;
}

Don't forget to include required libs, you should have some warnings when you're compiling which could have lead you to find an answer just by adding some include, and then you would have to find deeper to get a solution because new error would have been raised.

Ximaz
  • 198
  • 2
  • 9
-1

I recently came to the same problem and managed to solve it with an inline function (after having played a lot around var_arg, pointers, memory addresses and even pre-processor sentinel macros with a NULL marker). The help of jfjlaros and J-M-L Jackson from de Arduino community has been crucial to get to this (in my opinion, much clear and easy to deal with):

struct CIRCLE
{
  String name;
  double x;
  double y;
  int radius;
};

inline String drawCircle() {
  return "";
}

template <class... Circles>
String drawCircle(CIRCLE& c, Circles&... cs) {
  return c.name +','+ c.x +','+ c.y +','+ c.radius +';' + drawCircle(cs...);
}

void foo() {
  CIRCLE circle1 = {"circle1", 48.4, 7.14, 1};
  CIRCLE circle2 = {"circle2", 58.4, 17.14, 2};
  CIRCLE circle3 = {"circle3", 68.4, 27.14, 3};

  String str = drawCircle(circle1, circle2, circle3);  
  printf("Test1: %s\n", str); // will normally never work, except some times "per chance"
  printf("Test2: %s\n", str.c_str()); // '%s' is for a c-string not a String instance, therefore have to use 'str.c_str()' or change 'String str = "xxx"' to 'const char * s = "xxx"'
}
Paul Efford
  • 261
  • 4
  • 12