简体   繁体   English

如何获得va_arg的地址?

[英]How to get address of va_arg?

I hack some old C API and i got a compile error with the following code: 我破解了一些旧的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);
}

The error with gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9) was: gcc version 4.4.1 (Ubuntu 4.4.1-4ubuntu9)的错误是:

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

So why exactly it's not possible here to get a pointer to argument? 那么为什么这里不可能得到一个指向参数的指针呢?

How to fix it? 怎么解决? This code is executed very often with different OP* , so i prefer to not allocate extra memory. 这段代码经常使用不同的OP*执行,所以我更喜欢不分配额外的内存。

Is it possible to iterate over va_list knowing only the size of arguments? 只知道参数的大小,是否可以迭代va_list?

Change param_buffer to be an array of param_buffer更改为数组

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

Then you can say 然后你可以说

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
}

You can't get the address of a variadic arg. 你无法获得可变参数arg的地址。

Since litb's answer isn't useable for you because you can't modify the pexec() function, you could fix this using alloca() if your compiler provides it: 由于你不能修改pexec()函数,因为litb的答案对你不可用,你可以使用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() is usually blindingly fast, since it often is implemented using the same mechanism that is used to allocate space for local variables. alloca()通常非常快,因为它通常使用用于为局部变量分配空间的相同机制来实现。 The space will be automatically deallocated when the calling function exits. 当调用函数退出时,该空间将自动解除分配。

It won't be portable, but on some implementations, va_list is a char * to the address of the parameter on the stack. 它不可移植,但在某些实现中,va_list是堆栈上参数地址的char * Since some platforms pass arguments in registers, and due to stack alignment issues, you don't really want to do the following: 由于某些平台在寄存器中传递参数,并且由于堆栈对齐问题,您实际上并不想执行以下操作:

If this is for a single platform, you could look at its stdarg.h and hack up a solution to get to the address of the parameter on the stack. 如果这是针对单个平台的,您可以查看其stdarg.h并获取解决方案以获取堆栈上参数的地址。

Major hack though, and not really a good idea. 虽然很重要,但并不是一个好主意。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM