我破解了一些旧的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?
答案 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并修改一个解决方案来获取堆栈参数的地址。
重大黑客,但并不是一个好主意。