传递 std::vector<int>可变参数函数的项目 [英] Passing std::vector<int> items to variadic function

查看:37
本文介绍了传递 std::vector<int>可变参数函数的项目的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用 gcc 4.6.假设有一个参数向量 v​​ 我必须传递给可变参数函数 f(const char* format, ...).

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, ...).

这样做的一种方法是:

        void VectorToVarArgs(vector<int> &v)
        {
            switch(v.size())
            {
                case 1: f("%i",             v[0]);
                case 2: f("%i %i",          v[0], v[1]);
                case 3: f("%i %i %i",       v[0], v[1], v[2]);
                case 4: f("%i %i %i %i",    v[0], v[1], v[2], v[3]);

                // etc...
                default:
                    break;
            }
        }

        // where function f is
        void f(const char* format, ...)
        {
            va_list args;
            va_start (args, format);
            vprintf (format, args);
            va_end (args);
        }

问题当然是它不支持向量 v 中的任意数量的项目.但是,我相信已经了解 va_lists 原则上是如何工作的,即通过从堆栈中读取参数,从..."之前的最后一个命名参数的地址开始,现在我认为应该可以将向量项值复制到内存块(例如 myMemBlock)并将其地址作为格式"之后的第二个参数传递.显然,这将要求 myMemBlock 的结构符合 f() 的预期,即像堆栈一样.

The problem is of course that it does not support an arbitrary number of items in the vector v. However, I believe to have understood how va_lists works in principle, i.e. by reading the arguments from the stack, starting at the address of the last named argument prior to "...", Now I thought it should be possible to copy the vector item values to a memory block (e.g. myMemBlock) and pass it's address as the second argument after 'format'. Obviously that would require that myMemBlock to be structured as expected by f(), i.e. like a stack.

  1. 这样的事情可行吗?
  2. 或者,是否可以使用一些内联汇编魔法将向量项值推送到实际堆栈中,调用函数 f() 然后清理堆栈?

最后,我不关心的事情:

Finally, things I don't care about:

  1. 代码可能不可移植.好的,我只是对 gcc 感兴趣.
  2. 可能还有其他涉及预处理器黑客的方法.
  3. 不鼓励在 C++ 中使用像 printf() 这样的可变参数函数进行格式化.
  4. 可变参数模板函数的使用.

推荐答案

好的,这里是部分解决方案!部分,因为它不适用于 really 可变参数函数,但对于那些接受 va_list 作为参数的人.但我认为完整的解决方案并不遥远.

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. 动态创建 va_listhttps://bbs.archlinux.org/viewtopic.php?pid=238721

伪造一个 va_listhttp://confuseddevelopment.blogspot.com/2006/04/dynamically-creating-valist-in-c.html

此代码在 linux VC++2008 上使用 gcc 测试成功,其他平台也可能受支持,但这取决于您.

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

对我来说重要的见解是 va_list 基本上只不过是一个打包数组,可以动态填充数据,并且可以传递给函数,如vprintf, vfprintf, vsprintf 接受它作为参数.

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.

话虽如此,这里是动态分配堆栈的方法:

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

using namespace std;


class Format
{
    typedef vector<unsigned long> 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("
%x %s %x %c
") <<  etc. );
    cout <<= Format("
%x %s %x %c
") << 0x11223344 << "VectorToVarArg" << 0xAABBCCDD << '!';
    return 0;
}

猜猜它的作用是什么?它允许使用向量中收集的参数进行 printf(..) 样式格式化.是的,它并不完美,但它可以满足我的需求.此外,它涵盖了两个主要平台:D

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

另外,看看这篇文章:va_passhttp://www.codeproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a

这篇关于传递 std::vector&lt;int&gt;可变参数函数的项目的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆