所以我有两个函数都有相似的参数
void example(int a, int b, ...);
void exampleB(int b, ...);
现在example
调用exampleB
,但是如何在不修改的情况下传递变量参数列表中的变量exampleB
(因为该变量已经在其他地方使用过)。
所以我有两个函数都有相似的参数
void example(int a, int b, ...);
void exampleB(int b, ...);
现在example
调用exampleB
,但是如何在不修改的情况下传递变量参数列表中的变量exampleB
(因为该变量已经在其他地方使用过)。
Answers:
您不能直接做到;您必须创建一个包含以下内容的函数va_list
:
#include <stdarg.h>
static void exampleV(int b, va_list args);
void exampleA(int a, int b, ...) // Renamed for consistency
{
va_list args;
do_something(a); // Use argument a somehow
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...
}
, ...
签名中包含可变参数列表的函数。如果您已将变量参数转换为va_list
,则可以将传递va_list
给仅使用a的另一个函数va_list
,但是该函数(或它调用的函数)必须具有某种了解in中内容的方法va_list
。
也许在这里扔石头在池塘里,但是对于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++
。
args...
我还想包装printf并在这里找到一个有用的答案:
我对性能一点都不感兴趣(我敢肯定,可以通过多种方式来改进这段代码,可以随时这样做:)),这仅用于常规调试打印,所以我这样做:
//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 ++ ostream在某些方面很漂亮,但是如果您想用一些小字符串(例如括号,冒号和逗号插入数字之间)来打印这样的内容,这实际上会变得很可怕。
顺便说一下,许多C实现都有内部vprintf变体,恕我直言,IMHO应该是C标准的一部分。确切的细节有所不同,但是典型的实现将接受包含字符输出函数指针和说明将要发生的信息的结构。这允许printf,sprintf和fprintf都使用相同的“核心”机制。例如,vsprintf可能类似于:
无效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-> func;然后,输出函数可以将字符,文件,字符串或其他内容发送到控制台。如果某个人的实现公开了core_printf函数(及其使用的任何设置机制),则可以使用各种变体对其进行扩展。
这是唯一的方法。也是最好的方法。
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;
}