0

I'm kinda confused with the usage of <stdarg.h> features. I can't figure out how to properly pass a va_list to the argument function. Here's a simplified example of what I'm trying to achive:

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

void caller(int (*func)(size_t, ...), size_t n_args, ...) {
    va_list args;
    va_start(args, n_args);
    va_list args_for_func;
    va_copy(args_for_func, args);
    printf("(");
    for (size_t i = 0; i < n_args-1; i++) {
        printf("%i, ", va_arg(args, int));
    }
    printf("%i) => ", va_arg(args, int));
    int result = func(n_args, args_for_func);
    va_end(args_for_func);
    printf("%i", result);
    va_end(args);
}

int sum(size_t n_args, ...) {
    va_list args;
    va_start(args, n_args);
    int result = 0;
    for (size_t i = 0; i < n_args; i++) {
        result += va_arg(args, int);
    }
    va_end(args);
    return result;
}

int main() {
    // expected: (1, 2, 3, 4, 5) => 15
    // got: (1, 2, 3, 4, 5) => gibberish
    caller(sum, 5llu, 1, 2, 3, 4, 5);
}
3
  • Please note that the best practices is to never use variadic functions or stdarg.h for any purpose. It's a horribly error-prone feature that should never have been included in the language in the first place. Commented Oct 8, 2024 at 14:56
  • @Lundin how do you imagine something like printf without it? We could just concatenate the strings and do all the needed conversions manually, or there could be a bunch of separate toString-like functions for different data types. Both of these are notoriosly inconvenient Commented Oct 9, 2024 at 0:57
  • The need to do console I/O in professional applications is quite limited in general these days. But it's one thing to use the horribly designed standard lib - it is what it is - and another thing to invent new horribly designed libraries when there's no need for it. Commented Oct 9, 2024 at 6:24

2 Answers 2

2

A function can only process its variadic parameters using a va_list, and the parameters referenced by the va_list cannot be expanded out in a call to another variadic function. However, the va_list value can be passed by value to another function, so the way to solve the problem is to change the function pointer to point to a function that uses a va_list:

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

void caller(int (*func)(size_t, va_list), size_t n_args, ...) {
    va_list args;
    va_start(args, n_args);
    va_list args_for_func;
    va_copy(args_for_func, args);
    printf("(");
    for (size_t i = 0; i < n_args-1; i++) {
        printf("%i, ", va_arg(args, int));
    }
    printf("%i) => ", va_arg(args, int));
    int result = func(n_args, args_for_func);
    va_end(args_for_func);
    printf("%i", result);
    va_end(args);
}

int vsum(size_t n_args, va_list args) {
    int result = 0;
    for (size_t i = 0; i < n_args; i++) {
        result += va_arg(args, int);
    }
    return result;
}

int sum(size_t n_args, ...) {
    va_list args;
    va_start(args, n_args);
    int result = vsum(n_args, args);
    va_end(args);
    return result;
}

int main() {
    caller(vsum, 5llu, 1, 2, 3, 4, 5);
}
Sign up to request clarification or add additional context in comments.

Comments

1

You cannot chain vararg functions. Prototype of sum should be:

int sum(size_t n_args, va_list args)

And sum should not have va_start as va_copy already does the necessary procedures.

But you should reconsider if you really need vararg function. It has poor type safety, and usually it is better to pass array or other object instead.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.