Passing std::vector items to variadic function

前端 未结 5 1752
天涯浪人
天涯浪人 2021-01-17 17:26

I\'m using gcc 4.6. Assume that there is a vector v of parameters I have to pass to a variadic function f(const char* format, ...).

One approach of doing this is:

5条回答
  •  我在风中等你
    2021-01-17 17:56

    Okay, here is a partial solution! Partial, because it does not apply to really variadic functions, but to those which accept a va_list as argument. But I think the full solution isn't far away.

    It is based on the examples I found here:

    1. Dynamically create a va_list https://bbs.archlinux.org/viewtopic.php?pid=238721

    2. forge a va_list http://confuseddevelopment.blogspot.com/2006/04/dynamically-creating-valist-in-c.html

    This code is tested with gcc on linux and VC++2008 successfully, other platforms might be supported too, but that's up to you.

    The important insight for me was that a va_list is basically nothing more than a packed array, which can be filled with data dynamically and can be passed to functions like vprintf, vfprintf, vsprintf which accept it as argument.

    So passing vector items to one of those functions can work by allocating enough memory for the vector items and copy them over prior to the call.

    Having said that, here is the dynamically allocating stack approach:

    #include 
    #include 
    #include 
    #include 
    #include 
    #include 
    
    using namespace std;
    
    
    class Format
    {
        typedef vector ULVector;
        ULVector _args;
        string _format;
    
        public:
            Format(const char* format) : _format(format)
            {}
    
            Format &operator<<(int arg) {
                _args.push_back((unsigned long)arg);
                return *this;
            }
    
            Format &operator<<(const char* arg) {
                _args.push_back((unsigned long)arg);
                return *this;
            }
    
            string format() {
                union {
                    va_list varargs;
                    unsigned long* packedArray;
                } fake_va_list;
    
                // malloc would do it as well!
                // but alloca frees the mem after leaving this method
                unsigned long *p = (unsigned long*)alloca(_args.size() * sizeof(unsigned long));
                fake_va_list.packedArray = p;
    
                ULVector::iterator i = _args.begin();
                for (int n=0; i != _args.end(); i++, n++) {
                    p[n] = *i;
                }
    
                char buffer[512];
                const char* fmt = _format.c_str();
                vsprintf(buffer, fmt, fake_va_list.varargs);
    
                // place a free(p) here if you used malloc
                return string(buffer);
            }
    };
    
    
    ostream& operator <<=(ostream &os, Format &obj) {
          os << obj.format();
          return os;
    }
    
    
    int main()
    {
        // we use '<<=' operator here which has lower precedence than '<<'
        // otherwise we have to write
        // cout << ( Format("\n%x %s %x %c\n") <<  etc. );
        cout <<= Format("\n%x %s %x %c\n") << 0x11223344 << "VectorToVarArg" << 0xAABBCCDD << '!';
        return 0;
    }
    

    Guess what it does? It allows printf(..) style formatting with the parameters collected in a vector. Yes, it's not perfect but it does what I wanted. Furthermore, it covers two major platforms :D

    Additionally, have look at this article: va_pass http://www.codeproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a

提交回复
热议问题