路过的std ::矢量<&INT GT;项目可变参数函数 [英] Passing std::vector<int> items to variadic function

查看:219
本文介绍了路过的std ::矢量<&INT GT;项目可变参数函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我用gcc 4.6。
假设有一个参数向量v我要传递给可变参数函数f(为const char *格式,...)。

这样做的一种方法是:

 无效VectorToVarArgs(矢量<&INT GT;&安培; 5)
        {
            开关(v.size())
            {
                情况1:F(%i的,V [0]);
                案例2:F(%I%I,V [0],V [1]);
                情况3:F(%I%I%i的,V [0],V [1],V [2]);
                壳4:F(%I%I%I%i的,V [0],V [1],V [1],V [3]);                //等等...
                默认:
                    打破;
            }
        }        //其中函数f
        无效F(为const char *格式,...)
        {
            va_list的ARGS;
            的va_start(参数,格式);
            vprintf(格式参数);
            va_end用来(参数);
        }

问题当然是它不支持向量v项的任意数量的。
不过,我相信已经明白如何在原则va_lists作品,
即,通过从堆栈读取的参数,开始于最后一个命名参数之前的地址...,
现在,我认为这应该是可能的载体项目值复制到存储块(例如myMemBlock)
并通过它的地址作为格式化之后的第二个参数。
显然,这将要求myMemBlock用f(),即象一个堆栈按预期的结构


  1. 是这样的事情是可行的?

  2. 或者,是否有可能推进与一些内联汇编魔术真正的堆栈中的向量项值,
    调用函数f()和事后清理堆栈?

最后,事情我不关心:


  1. 的code可能是不可移植的。 OK,我在GCC只是有兴趣。

  2. 有可能是涉及到preprocessor两轮牛车其他方法。

  3. 格式化如printf()可变参数函数的用法不被鼓励使用C ++。

  4. 的可变参数模板函数的用法。


解决方案

好吧,这里是一个局部的解决方案!
局部的,因为它并不适用于的真正的可变参数的功能,
但那些接受的va_list作为参数。
但我认为,完整的解决方案就在不远处。

这是基于我发现这里的例子:


  1. 动态创建的va_list
    https://bbs.archlinux.org/viewtopic.php?pid=238721


  2. 伪造的va_list
    http://confuseddevelopment.blogspot.com/2006/04/dynamically-creating-valist-in-c.html


这code是在Linux上的gcc的测试 VC ++ 2008成功,
其他平台可能过于支持,但是这取决于你。

对于我来说最重要的观点是的va_list基本上没有什么比一个压缩阵列多,
可以动态填充有数据,并且可以被传递到功能,如
vprintf,vfprintf,vsprintf中它接受它作为参数。<​​/ P>

所以,通过矢量项目的这些功能​​可以通过分配足够的内存运行
为载体的项目和对现有复制他们的电话。

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

 的#include&LT;&iostream的GT;
#包括LT&;&stdio.h中GT;
#包括LT&;&STDARG.H GT;
#包括LT&;串GT;
#包括LT&;矢量&GT;
#包括LT&;&alloca.h GT;使用命名空间std;
类格式
{
    typedef的矢量&lt;无符号长&GT; ULVector;
    ULVector _args;
    串_format;    上市:
        格式(为const char *格式):_format(格式)
        {}        格式和放大器;运营商LT;≤(INT ARG){
            _args.push_back((无符号长)ARG);
            返回*这一点;
        }        格式和放大器;运营商LT;≤(为const char * ARG){
            _args.push_back((无符号长)ARG);
            返回*这一点;
        }        字符串格式(){
            工会{
                va_list的可变参数;
                无符号长* packedArray;
            } fake_va_list;            // malloc的会做得一样好!
            //但离开的alloca此方法后释放纪念品
            无符号长* P =(无符号长*)的alloca(_args.size()* sizeof的(无符号长));
            fake_va_list.packedArray = P;            ULVector:迭代I = _args.begin();
            对于(INT N = 0;!I = _args.end();我+ +,N ++){
                P [N] = *我;
            }            字符缓冲区[512];
            为const char * FMT = _format.c_str();
            vsprintf中(缓冲,格式化,fake_va_list.varargs);            //放置一个免费的(P)在这里,如果你使用的malloc
            返回的字符串(缓冲);
        }
};
ostream的&安培;运营商的LT;&LT; =(ostream的&放大器; OS,格式和放大器; OBJ){
      OS&LT;&LT; obj.format();
      返回操作系统;
}
诠释的main()
{
    //我们使用'&LT;&LT; ='在这里操作者具有较低的precedence比'&LT;&LT;'
    //否则,我们不得不写
    // COUT&LT;&LT; (格式(\\ n%X%S%X%C \\ n)&LT;&LT;等等);
    COUT&LT;&LT; =格式(\\ n%X%S%X%C \\ n)&LT;&LT; 0x11223344&LT;&LT; VectorToVarArg&LT;&LT; 0xAABBCCDD&LT;&LT; !;
    返回0;
}

猜猜是什么呢?
它允许在一个载体收集到的参数的printf(..)样式格式。
是的,它并不完美,但它确实是我想要的。
此外,它包括两个主要的平台:D

此外,有看看这篇文章:
va_pass
http://www.$c$cproject.com/Articles/9968/va_list-va_start-va_pass-or-how-to-pass-variable-a

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:

        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);
        }

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. Is such a thing doable?
  2. Alternatively, is it possible to push the vector item values on the real stack with some inline assembler magic, call function f() and clean up the stack afterwards?

Finally, things I don't care about:

  1. The code might be not portable. OK I'm just interested in gcc.
  2. There might be other approaches involving preprocessor hackery.
  3. Usage of variadic function for formatting like printf() does, is discouraged for C++.
  4. Usage of variadic template functions.

解决方案

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 <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("\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

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

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