tags:

views:

296

answers:

7

All:

I have faced such a problem. I have a function

void foo(int cnt, va_list ap);

I need to use it, and but requirement is quite strict, number of va_list vary and it will change during run-time. What I would like to do is:

create a va_list (which expects char*) form

QList<Contact*>

where Contact is a defined class

class Contact
{
   public:
      QString getName();
   private: 
      QString m_name;

}; 

and I would like to populate in the loop va_list for example:

for (int idx = 0; idx<contacts.count(); idx++)
{
    contacts.at(idx)->getName(); // this i would like to pass to va_list

}

Has anybody have a clue how could I do this? Thanks in advance!!

Lukasz

A: 

If the number of elements in the list is limited, I would go for manual dispatch depending on the number of elements.

void call_foo(int count, ...) {
    va_list args;
    va_start(args, count);
    foo(count, args);
    va_end(args);
}

switch (contacts.count()) {
    case 0: return call_foo(contacts.count());
    case 1: return call_foo(contacts.count(),
                            contacts.at(0)->getName());
    case 2: return call_foo(contacts.count(),
                            contacts.at(0)->getName(),
                            contacts.at(1)->getName());
    case 3: return call_foo(contacts.count(),
                            contacts.at(0)->getName(),
                            contacts.at(1)->getName(),
                            contacts.at(2)->getName());
    default: /* ERROR HERE, ADD MORE CASES */ return call_foo(0);
}
Didier Trosset
There reason for this is not the most efficient way to do this is:I can have 1-999 elements Contact and this would look pretty ugly. I was hoping to find better-efficient solution.Rgds Lukasz
I am not certain it is *better-efficient* to call a function with 999 parameters.
Didier Trosset
Are you sure that the foo function in the library will be able to handle a va_list with 999 parameters?
Didier Trosset
Joe D
A: 

There reason for this is not the most efficient way to do this is:

I can have 1-999 elements Contact and this would look pretty ugly. I was hoping to find better-efficient solution.

Rgds Lukasz

I am not certain it is better-efficient to call a function with 999 parameters.
Didier Trosset
A: 

It depends on compiler what is the va_list type, what are the va_start and va_end macros. You cannot do this in a standard way. You would have to use compiler-specific construction.

Maybe you can alter the 'foo' function? If so, then make it inversely - convert va_list to QList and make 'foo' accept QList.

// EDIT

Then see what the va_list type is, what the va_start and va_end macros are in your specific compiler. Then build your va_list in such a way that these macros will work on it.

adf88
I could actually expect that.I develop QT app for Windows IDE: Visual Studio 2005.
I cannot do this, this if function which is exposed by LIB :). I do not have a source code for it.
I cannot do this, this is function which is exposed by LIB :). I do not have a source code for it.
I made some editing, read my answer again.
adf88
+1  A: 

Your question is tagged C++ and there are nice ways (like streams) to avoid varargs completely in C++.

This is a great example of why va_args can cause pain. If you have any chance at all to change the signature of foo, that's your best option. Taking a std::vector<std::string> instead of va_list would just solve your problem right there.

If foo is in an external library you can't change, my next suggestion would be to find a different library.

If none of those is an option it seems like there ought to be a way to recursively build up the call list using va_list, but I couldn't figure out how to make that work.

Mark B
A: 

What you're wanting to do is to simulate the call stack so you can pass a constructed va_list to foo(). This is rather specific to the compiler ( and warning, there are differences between even 32- and 64-bit compilers ). The following code is for ENTERTAINMENT PURPOSES ONLY!!! as (if it even works on your system) it is prone to breakage. With it, I use a flat memory buffer and the populate it with a count and a bunch of character strings. You could fill it as appropriate with pointers to your strings and hand them down.

It does seem to work on my system, Windows 7 w/ Visual Studio 2008, for 32-bit applications only.

* BAD IDEA CODE FOLLOWS!!! *

#define PSEUDOSTACKSIZE ( sizeof(int) + 999 * sizeof(const char*) )
#pragma pack( push,1 )
union PSEUDOSTACK
{
    int count;
    char data[PSEUDOSTACKSIZE];
};
#pragma pack( pop )

void foo( int count, va_list args )
{
    for ( int i = 0; i < count; i++ )
    {
        char *s = va_arg( args, char* );
        printf( "%s\n", s);
    }
}

void bar( PSEUDOSTACK data, ... ) 
{ 
    va_list args; 
    va_start(args, data.count); 
    foo( data.count, args);
    va_end(args); 
} 
// And later on, the actual test case code.
PSEUDOSTACK barData;
barData.count = 999;
char *p = barData.data + sizeof(int);
for ( int i = 0; i < 999; i++, p += sizeof(char*) )
{
    *reinterpret_cast<char**>(p) = "ThisIsABadIdea";
}
bar( barData );

I'll now go hang my head in shame for thinking of such an idea.

Gimble
A: 

<just for fun>

  • allowing arbitrary argument count
  • luckily sizeof(std::wstring) is a multiple of sizeof(int)
  • tested on w2k3 sp2 32bit + visual c++ 2010

#include <stdarg.h>
#include <string>
#include <vector>
#include <iostream>

#define N 6 // test argument count

void foo(int n, ...);

int main(int, char*[])
{
    std::vector strings;
    std::wstring s(L"a");
    int i(0);

    // create unique strings...
    for (; i != N; ++i)
    {
        strings.push_back(s);
        ++s.front();
    }

    int n_stack_strings(N*sizeof(std::wstring)),    // space needed for strings
        n_stack(sizeof(int)+n_stack_strings);   // overall stack space...needed for cleanup

    __asm sub esp, n_stack_strings  ; reserve stack space

    std::wstring* p_stack(0);

    __asm mov p_stack, esp  ; get stack pointer

    std::wstring* p(p_stack);
    std::vector<std::wstring>::iterator string(strings.begin());

    // copy to stack
    for (; string != strings.end(); ++string, ++p)
        new (p) std::wstring(*string);
    __asm push N    ; argument count...arguments right to left (__cdecl)
    __asm call foo
    // cleanup
    for (p = p_stack; p != p_stack+N; ++p)
        p->~basic_string();
    __asm add esp, n_stack  ; caller has to cleanup the stack (__cdecl)
    return 0;
}

void foo(int n, ...)
{
    int i(0);
    va_list marker;

    va_start(marker, n);
    for (; i != n; ++i)
        std::wcout << va_arg(marker, std::wstring) << std::endl;
    va_end(marker);
}

</just for fun>

slow
A: 
slow