3

A function with the following header:

int max(int n, va_list vals)

Called inside the function:

int max_first(int n, ...)

Needs a va_start(vals, n) invocation at the body's beginning? I tried without and it works but I don't understand which is the correct way of doing it.

int max(int n, va_list vals)
{
    va_start(vals, n);
    // etc
}

3 Answers 3

6

The question is if

int max(int n, va_list vals)

Called inside the function:

int max_first(int n, ...)
 

Needs a va_start(vals, n) invocation at the body's beginning?

No, it does not and it must not, the correct pattern is as follows:

int max_first(int n, ...) {
    va_list vals;
    va_start(vals, n);
    int rv = max(n, vals);
    va_end(vals);
    return rv;
}

then

int max(int n, va_list vals) {
    for (int i = 0; i < n; i ++) {
        int val = va_arg(vals, int);
        ...
    }

    ...
}

i.e. you can call va_start only in a function that has ... and you need to pass in the argument immediately preceding the ..., and each call to va_start must be always followed by va_end for the same value, and if you pass it to a function then you must call va_end right afterwards without using it in the calling function; if you want to process the arguments again, you must then call va_start again.

Sign up to request clarification or add additional context in comments.

Comments

4

You must initialize va_list with va_start in max_first. But you must not redo it in max, because that function doesn't have necessary callframe information.

2 Comments

that function doesn't have necessary callframe information. What do you mean ?
@CătălinaSîrbu You have to pass last non variable argument (n in max_first) to va_start, which it will use to calculate address of first possible variable argument. Your another function max doesn't have that variable (that n is different).
3

Let's start with some background: per the documentation, you need to call va_start before invoking va_arg on any va_list:

  • "va_start should be invoked with an instance to a valid va_list object ap before any calls to va_arg". (Source)

  • "Prior to calling va_arg, ap must be initialized by a call to either va_start or va_copy, with no intervening call to va_end". (Source)

I would imagine not calling va_start is undefined behavior, but I couldn't find a specific callout to state as such.

In your question, the function int max(int n, va_list vals) is not "really" variadic, since it accepts a fixed number of arguments: 2. These are int n and va_list vals.

Per the documentation "The declaration of a variadic function uses an ellipsis as the last parameter, e.g. int printf(const char* format, ...);"

So, it depends on how you implement it, but I would recommend documenting the int max(int n, va_list vals) to accept a va_list that is already initialized with a va_start call. The rationale being that it is not technically "variadic" and does not really "own" the va_list. It just accepts it as an input from some other source.

The actual variadic function int max_first(int n, ...) should be the one creating the va_list and priming it with the call to va_start before passing it anywhere.

Although, as far as I can tell, there's no way to check if a va_list already has va_start called on it or not. And there's no guarantee that it will be called before being passed to your function, so I suspect this would have to be enforced by documentation and convention.

4 Comments

A note on formatting: ` ≠ ". Backticks are there exclusively to highlight code (and other monospaced stuff, e.g. paths)
Thank you! After reading your answer, some questions came into my mind: It is perfectly fine to call int max from int max_first before max_first calling va_start? also, calling twice va_start (once in max and second in max_first) is a problem ?
You can format quotes on separate paragraphs prefixing the lines with >
@CătălinaSîrbu - you should call va_start in max_first before passing it to max. And you should not call va_start twice without first having a call to va_end. This is called out in the C11 specification, as mentioned here stackoverflow.com/a/59608709/1366973. Otherwise it is undefined behavior.

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.