在va_list对象中包含First Argument

时间:2016-06-24 23:30:44

标签: c++ variadic-functions

是否可以在va_list中包含函数的第一个参数?我想将参数从一个函数传递给另一个函数。

int main(){
    test(1,2,3,4,5,-1);
}

void test(int firstArg, ...){
    va_list va;
    va_start(va, firstArg);
    passFunction(va);
}

void passFunction(va_list va){
    int x;    
    while((x = va_arg(ap,int))!=-1){
        cout << x << endl;  
    }
}

我想要的输出:

1
2
3
4
5

实际输出:

2
3
4
5

有没有办法在没有明确地将第一个参数传递给函数的情况下实现这个目的?

1 个答案:

答案 0 :(得分:0)

va_start()需要一个固定参数,并将va_list初始化为指定参数后面的 next 参数。由于您的函数只有一个固定参数,因此无法使用库存va_list将其包含在va_start()中,因为前面没有固定参数。

仅限32位(64位更复杂),您可以将编译器的va_start()源代码从varargs.hstdargs.h(或等效代码)复制到您的自己的源文件,然后调整它以使用指定参数本身的地址而不是其后的地址初始化va_arg

例如,在C ++ Builder中,va_start()定义为:

#ifdef __cplusplus
#define va_start(ap, parmN) ((void)((ap) = (std::va_list)((char _FAR *)(&parmN)+__size(parmN))))
#else
#define va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN)+__size(parmN))))
#endif

所以你只需删除+__size(parmN)部分:

#ifdef __cplusplus
#define my_va_start(ap, parmN) ((void)((ap) = (std::va_list)((char _FAR *)(&parmN))))
#else
#define my_va_start(ap, parmN) ((void)((ap) = (va_list)((char _FAR *)(&parmN))))
#endif

在Visual Studio中,va_start()定义为:

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INSIZEOF(v) )
#define va_start _crt_va_start

所以你只需删除+ _INSIZEOF(v)部分:

#define my_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) )

GCC实际上使用编译器内部函数而不是宏,因此您可能无法获取其va_start()源,但生成的代码应该类似于cdecl调用约定(唯一的调用约定)支持32位的可变参数在编译器中相当标准化。

无论哪种方式,预处理器生成的代码最终都会大致相同,所以如果它与你的编译器兼容,你可以直接编写代码:

void test(int firstArg, ...){
    va_list va = (va_list) &firstArg;
    passFunction(va);
}