简体   繁体   中英

how to pass and access a struct to a variadic function in C

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

You're using 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);
    }

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.

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 JML 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"'
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM