简体   繁体   中英

Printing function with variable number of arguments

I have this function:

void print(THashEntry *entry, ...)
{
    va_list parameters;

    va_start(parameters, entry);

    while (true)
    {
        THashEntry *currentEntry = va_arg(parameters, THashEntry *);
        if (!currentEntry)
        {
            break;
        }

        printf("%s\n", currentEntry->value);
    }



 va_end(parameters);
}

I pass adresses of these entries into the function and then I want to access their member "value" and print it.

However when I try to obtain a parameter via va_arg, it returns me not the first, but the second parameter right from the start and when another loop of cycle goes in, it's segmentation fault.

As John Kugelman states in his answer , here are some of the good practices to pass variable number of arguments to printf/sprintf:-

 void Error(const char* format, ...)
 {
  va_list argptr;
  va_start(argptr, format);
  vfprintf(stderr, format, argptr);
  va_end(argptr);
 }

va_arg won't return NULL when you reach the end of argument list. As man va_arg says:

random erros will occur

So to get around it you either need to pass number of arguments to your print function, or end terminator.

To automatically calculate number of arguments at compile time, you can use macro

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

See more details in this answer

I apologize for butting into your design but this might be an alternative to use

 struct abc {
    int a;
    char b[10];
 };

 void f(int size, abc* a) {
    for (int i = 0; i < size; i++) {
    abc x = a[i];
    }
 }

int _tmain(int argc, _TCHAR* argv[])
{
abc *arrAbc = new abc[10];
for (int i = 0; i < 10; i++) {
    arrAbc[i].a = 0;
}
f(10, arrAbc);
}

Seems like there are quite a few answers, but personally I've never found a great way to get around dynamically counting the number of args in a va_list.

That said, there are several ways around it:

  • Use the NUMARGS(...) macro as noted by qrdl
  • Pass the number of args into the function like as main does void print(int numArgs, MyEntry *entry, ...)
  • Use a NULL terminated list

The latter happens to be my personal preference, since it tends to go with my (and it looks like yours too) instinct to how to catch the end of the list. See below:

 #import <stdarg.h>

 typedef struct MyEntry {
     int a;
     int b;
 } MyEntry;

 void print(int numArgs, MyEntry *entry, ...) {

     va_list parameters;

     va_start(parameters, entry);

     MyEntry *m;
     for ( m = entry; m != NULL; m = va_arg(parameters, MyEntry *))  {        
         printf("%d\n", (int)m->a);
     }

     va_end(parameters);
 }

 int main(int argc, char *argv[]) {

     MyEntry entry = { 10, 20 };
     MyEntry entry2 = { 30, 40 };
     MyEntry entry3 = { 50, 60 };
     MyEntry entry4 = { 70, 80 };
     MyEntry entry5 = { 90, 100 };

     print(2, &entry, &entry2, &entry3, &entry4, &entry5, NULL);
     return 1;
 }

Happy coding!

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