将变量参数传递给另一个接受变量参数列表的函数

时间:2010-08-20 12:22:06

标签: c++ variadic-functions

所以我有2个函数都有相似的参数

void example(int a, int b, ...);
void exampleB(int b, ...);

现在example调用exampleB,但是如何在不修改exampleB的情况下传递变量参数列表中的变量(因为这已经在别处使用过了)。

9 个答案:

答案 0 :(得分:104)

你不能直接这样做;你必须创建一个带va_list

的函数
#include <stdarg.h>

static void exampleV(int b, va_list args);

void example(int a, int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

void exampleB(int b, ...)
{
    va_list args;
    va_start(args, b);
    exampleV(b, args);
    va_end(args);
}

static void exampleV(int b, va_list args)
{
    ...whatever you planned to have exampleB do...
    ...except it calls neither va_start nor va_end...
}

答案 1 :(得分:19)

也许在这里扔一个池塘里的岩石,但它似乎对C ++ 11可变参数模板工作得很好:

#include <stdio.h>

template<typename... Args> void test(const char * f, Args... args) {
  printf(f, args...);
}

int main()
{
  int a = 2;
  test("%s\n", "test");
  test("%s %d %d %p\n", "second test", 2, a, &a);
}

至少,它适用于g++

答案 2 :(得分:15)

你应该创建这些函数的版本,这些函数采用va_list,并传递它们。以vprintf为例:

int vprintf ( const char * format, va_list arg );

答案 3 :(得分:4)

我也想包装printf并在这里找到一个有用的答案:

How to pass variable number of arguments to printf/sprintf

我对性能一点都不感兴趣(我确信这段代码可以通过多种方式进行改进,随意这样做:)),这只适用于一般的debugprinting,所以我这样做了: / p>

//Helper function
std::string osprintf(const char *fmt, ...)
{
    va_list args;
    char buf[1000];
    va_start(args, fmt);
    vsnprintf(buf, sizeof(buf), fmt, args );
    va_end(args);
    return buf;
}

我可以像这样使用

Point2d p;

cout << osprintf("Point2d: (%3i, %3i)", p.x, p.y);
instead of for example:
cout << "Point2d: ( " << setw(3) << p.x << ", " << p.y << " )";

c ++ ostreams在某些方面很漂亮,但实际上如果你想在这些数字之间插入一些小字符串(例如括号,冒号和逗号)来打印这样的东西,那就太可怕了。

答案 4 :(得分:2)

顺便提一下,许多C实现都有内部v?printf变体,恕我直言应该是C标准的一部分。具体细节各不相同,但典型的实现将接受包含字符输出函数指针的结构和说明应该发生什么的信息。这允许printf,sprintf和fprintf都使用相同的“核心”机制。例如,vsprintf可能类似于:

void s_out(PRINTF_INFO *p_inf, char ch)
{
  (*(p_inf->destptr)++) = ch;
  p_inf->result++;
}

int vsprintf(char *dest, const char *fmt, va_list args)
{
  PRINTF_INFO p_inf;
  p_inf.destptr = dest;
  p_inf.result = 0;
  p_inf.func = s_out;
  core_printf(&p_inf,fmt,args);
}

core_printf函数然后为要输出的每个字符调用p_inf-&gt; func;然后输出函数可以将字符发送到控制台,文件,字符串或其他内容。如果一个人的实现暴露了core_printf函数(以及它使用的任何设置机制),可以使用各种变体扩展它。

答案 5 :(得分:0)

基于你正在包装vsprintf的评论,并且这被标记为C ++我建议不要尝试这样做,但是改变你的界面以改为使用C ++ iostreams。它们优于print函数系列,例如类型安全性,并且能够打印printf无法处理的项目。现在进行一些返工可以在将来节省大量的痛苦。

答案 6 :(得分:0)

一种可能的方法是使用#define:

#define exampleB(int b, ...)  example(0, b, __VA_ARGS__)

答案 7 :(得分:-1)

使用新的C ++ 0x标准,您可以使用可变参数模板完成此操作,甚至可以将旧代码转换为新的模板语法而不会破坏任何内容。

答案 8 :(得分:-1)

这是唯一的方法。也是最好的方法。

static BOOL(__cdecl *OriginalVarArgsFunction)(BYTE variable1, char* format, ...)(0x12345678); //TODO: change address lolz

BOOL __cdecl HookedVarArgsFunction(BYTE variable1, char* format, ...)
{
    BOOL res;

    va_list vl;
    va_start(vl, format);

    // Get variable arguments count from disasm. -2 because of existing 'format', 'variable1'
    uint32_t argCount = *((uint8_t*)_ReturnAddress() + 2) / sizeof(void*) - 2;
    printf("arg count = %d\n", argCount);

    // ((int( __cdecl* )(const char*, ...))&oldCode)(fmt, ...);
    __asm
    {
        mov eax, argCount
        test eax, eax
        je noLoop
        mov edx, vl
        loop1 :
        push dword ptr[edx + eax * 4 - 4]
        sub eax, 1
        jnz loop1
        noLoop :
        push format
        push variable1
        //lea eax, [oldCode] // oldCode - original function pointer
        mov eax, OriginalVarArgsFunction
        call eax
        mov res, eax
        mov eax, argCount
        lea eax, [eax * 4 + 8] //+8 because 2 parameters (format and variable1)
        add esp, eax
    }
    return res;
}