Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Create va_list dynamically

I have a function

void foo(int cnt, va_list ap);

I need to use it, 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

}

Does anybody have a clue about how I could do this?

like image 877
user404251 Avatar asked Jul 28 '10 08:07

user404251


2 Answers

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.

like image 79
Joe Marley Avatar answered Nov 07 '22 19:11

Joe Marley


...hmmm...maybe not portable...for sure not nice...but may solve yor problem...

  • va_list is (at least for visual c++) just a #define for char*
  • → arguments don't need to be on the stack
  • → arguments are just required to be continuous in memory
  • → no need to use assembler and/or copying (see my 'just for fun answer' :-)
  • → no need to worry about cleanup
  • efficient!
  • tested on w2k3 sp2 32bit + vc++ 2010

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

#define N 6 // test argument count

void foo(int n, va_list args);

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

    // create unique strings...
    for (; i != N; ++i)
    {
        strings.push_back(s);
        ++s.front();
    }
    foo(N, reinterpret_cast<va_list>(strings.data()));
    return 0;
}

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

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

like image 28
slow Avatar answered Nov 07 '22 19:11

slow