如何获得va_arg的地址?

时间:2010-04-19 21:00:56

标签: c variadic-functions

我破解了一些旧的C API,并且使用以下代码出现了编译错误:

void OP_Exec( OP* op , ... )
{
    int i;
    va_list vl;
    va_start(vl,op);
    for( i = 0; i < op->param_count; ++i )
    {
        switch( op->param_type[i] )
        {
            case OP_PCHAR:
                op->param_buffer[i] = va_arg(vl,char*); // ok it works
            break;
            case OP_INT:
                op->param_buffer[i] = &va_arg(vl,int); // error here
            break;
            // ... more here
        }
    }
    op->pexec(op);
    va_end(vl);
}

gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)出错  是:

 main.c|55|error: lvalue required as unary ‘&’ operand

那么为什么这里不可能得到一个指向参数的指针呢?

如何解决?这段代码经常使用不同的OP*执行,所以我更喜欢不分配额外的内存。

是否可以仅知道参数的大小来迭代va_list?

3 个答案:

答案 0 :(得分:2)

param_buffer更改为

数组
struct ValueUnion {
  Type type;
  union {
    char *stringval;
    int intval;
  } u;
};

然后你可以说

op->param_buffer[i].type = op->param_type[i];
switch( op->param_type[i] )
{
    case OP_PCHAR:
        op->param_buffer[i].u.stringval = va_arg(vl,char*); // ok it works
    break;
    case OP_INT:
        op->param_buffer[i].u.intval = va_arg(vl,int); // ok it works
    break;
    // ... more here
}

您无法获取可变参数arg的地址。

答案 1 :(得分:2)

由于litb's answer不可用,因为您无法修改pexec()函数,如果您的编译器提供alloca(),您可以使用 switch( op->param_type[i] ) { int *itmp; case OP_PCHAR: op->param_buffer[i] = va_arg(vl,char*); // ok it works break; case OP_INT: itmp = alloca(sizeof(int)); *itmp = va_arg(vl, int); op->param_buffer[i] = itmp; break; // ... more here } 来解决此问题:

alloca()

{{1}}通常非常快,因为它通常使用用于为局部变量分配空间的相同机制来实现。当调用函数退出时,该空间将自动解除分配。

答案 2 :(得分:0)

它不可移植,但在某些实现中,va_list是堆栈上参数地址的char *。由于某些平台在寄存器中传递参数,并且由于堆栈对齐问题,您实际上并不想执行以下操作:

如果这是针对单个平台的,你可以查看它的stdarg.h并修改一个解决方案来获取堆栈参数的地址。

重大黑客,但并不是一个好主意。