3

This is my first time working with va_list and stuff so I don't really know what I'm doing. Okay basically what I have is a bunch of numbers (1, 2, 3, 4, 5) in the function ordered and I get them to print out. This works fine.

#include <iostream>
#include <cstdarg>

using namespace std;

void ordered(int num1, double list ...);

void main()
{ 
    ordered(5, 1.0, 2.0, 3.0, 4.0, 5.0);
}

void ordered(int num1, double list ...)
{
    va_list arguments;

    va_start(arguments, num1);

    list = va_arg(arguments, double);
    cout << "There are " << num1 << " numbers" << endl;

    do { 
        cout << list << endl; // prints out 1 then 2 then 3 then 4 then 5
        list = va_arg(arguments, double);
    } while (list != 0);

    // at this point, list = 0

    va_end(arguments);
}

the problem is, after the va_end(arguments); or before it, I would like to get the program to print out my list a second time; basically print out 1, 2, 3, 4, 5 once more, without making another function. I tried to duplicate the code:

va_start(arguments, num1);

do { 
    cout << list << endl;
    list = va_arg(arguments, double);
} while (list != 0);

va_end(arguments);

without success. How can the program to repeat list once more, or is it not possible to do it again in the same function?

joce
  • 9,624
  • 19
  • 56
  • 74
im dumb
  • 151
  • 1
  • 4
  • 9
  • 1
    Good question actually, but i guess you also have to repeat the `va_start` and `va_end` part also. – RedX Mar 27 '13 at 13:21
  • I tried that but it didn't work :( alright i just edited the code to show that – im dumb Mar 27 '13 at 13:24
  • I don't think the signature of the function is right. `void ordered(int x, double y...)` means `void ordered(int x, double y, ...)`. That is, the varargs is not a sequence of `double`, but a sequence of unknown types that comes after a double argument. At the same time this means that your implementation is incorrect (drops the second argument to the function) – David Rodríguez - dribeas Mar 27 '13 at 13:32
  • Have you considered variadic templates instead which is type-safe compared to `va_arg` etc... http://stackoverflow.com/questions/276188/variadic-templates – Shafik Yaghmour Mar 27 '13 at 13:44
  • this is actually a homework assignment, gotta follow specific instructions :P – im dumb Mar 27 '13 at 13:50

3 Answers3

5

Here is a working implementation:

#include <iostream>
#include <cstdarg>

using namespace std;

void ordered(int num1, ...); // notice changed signature


int main(int,char**)
{ 
    ordered(5, 1.0, 2.0, 3.0, 4.0, 5.0);
    return 0;
}

void ordered(int count, ...) // notice changed signature
{
    va_list arguments;

    va_start(arguments, count);

    cout << "There are " << count << " numbers" << endl;

    double value = 0.0;

    // notice how the loop changed
    for(int i = 0; i < count; ++i) { 
        value = va_arg(arguments, double); 
        cout << value << endl; // prints out 1 then 2 then 3 then 4 then 5
    } 

    // at this point, list = 0

    va_end(arguments);

    va_list arg2;
    va_start(arg2, count);

    cout << "There are " << count << " numbers" << endl;

    for(int i = 0; i < count; ++i) { 
        value = va_arg(arg2, double);
        cout << value << endl; // prints out 1 then 2 then 3 then 4 then 5
    } 

    // at this point, list = 0

    va_end(arg2);

}
RedX
  • 14,749
  • 1
  • 53
  • 76
3

From the man page:

va_end()

Each invocation of va_start() must be matched by a corresponding invocation of va_end() in the same function. After the call va_end(ap) the variable ap is undefined.

Multiple traversals of the list, each bracketed by va_start() and va_end() are possible.

Could you show the code where you tried that but it didn't work?

NB. See also va_copy, with which you can make a duplicate of arguments before (destructively) traversing it, and then also traverse the duplicate.

Useless
  • 64,155
  • 6
  • 88
  • 132
1

The simple answer (ignoring how varargs really works, I find it hard to find a valid use case outside of printf) is to copy the arguments yourself. Well, actually a simpler answer would be not to use varargs at all... Why are you not passing a container (or in C++11 using an initializer_list?)

David Rodríguez - dribeas
  • 204,818
  • 23
  • 294
  • 489
  • And of course, even for `printf`, with C++11 variadic templates there's hardly any justification to using varargs... – Matthieu M. Mar 28 '13 at 07:03
  • @MatthieuM. I have not seen any implementation I like of `printf` without variadic args... Well, really I have not seen many implementations either. But currently the best candidate is a variadic args wrapper around `printf` that does the type checking and then forwards to the real `printf`, giving both the type safety of variadic templates and the performance of `printf` (in release mode the type tests can be `#ifdef`-ed out) – David Rodríguez - dribeas Mar 28 '13 at 12:15
  • There is little benefit to that, given that compilers have specific checks for it. I think the main issue is that nobody really gave a thought to it; and personally if I went into recoding `printf`, I would probably take the opportunity to update the format string in order to cater to *objects* as well as plain data types (which is one of `printf` main flaws). – Matthieu M. Mar 28 '13 at 12:35