2013-10-15 43 views
2

我试图写如printf C风格的可变参数函数,它增加了一些额外的参数的包装,但我用起来麻烦:添加额外的参数给C风格的参数可变参数列表

void printf(char* fmt, ...); // the thing I'm trying to wrap 

void wrapper(char* fmt, ...) 
{ 
    printf(fmt, extra_arg1, extra_arg2, /* the variadic arguments */); 
} 

但我要为/* the variadic arguments */写什么?

即使我想换行功能有一个版本,需要一个va_list,我不能这样做:

void vprintf(char* fmt, va_list args); 

void wrapper(char* fmt, ...) 
{ 
    va_list args; 
    va_start(args, fmt); 
    vprintf(fmt, extra_arg1, extra_arg2, args); 
    va_end(args); 
} 

extra_arg1extra_arg2args不会神奇地变成一个va_listvprintf预计。

我知道我可以写一个宏,使用__VA_ARGS__

,但我想,以避免和写入包装的功能。有没有办法做到这一点?

(顺便说一句,我不能使用C++ 11个可变参数模板无论是。)

+0

你已经看过这里:http:// stackoverflow。com/a/150616/2036917 –

+0

@UdoKlein:这个问题只是建议使用'va_list'。我已经知道了,问题是我需要**添加**参数,并且我不知道该怎么做。 – HighCommander4

+0

我不明白为什么你需要使用一个'vprintf'语句。据我所知,你的'wrapper'的额外参数也只是可变的,以便打印正确吗?为什么你不能使用单独的打印语句,或者更好的方式是将它们包含在'wrapper'调用的格式中? – Pankrates

回答

0

我看不出什么毛病,使用宏,不过这只是我:)

任何方式,有一种做法。 如果您不关心可移植性,则可以使用内联汇编。 变量函数使用cdecl调用调用,这意味着调用者负责将参数推送到堆栈上,而不是在被调用者返回后清除堆栈。 因此,一个简单的printf调用

printf("%d, %d, %d", 1, 2, 3) 

看起来像:

char format[] = "%d, %d, %d"; 
__asm { 
    push 3 
    push 2 
    push 1 
    lea eax, [format] 
    push eax 
    call printf 
    add esp,10h 
} 

注意最后PARAM推用于通过va_start来获取对栈的地址和va_arg只是通过参数迭代。

您可以使用相同的行为,并再次推可变参数:从

char new_format[] = "%d, %d, %d, %d, %d"; 
wrapper(new_format, ...) { 
    char *va = addressof(new_format)+sizeof(char*); // first argument after new_format 
    int i; 

    __asm { 
    push extra2 
    push extra1 
    } 
    for(i=0; i < num_of_arguments; i++) 
    __asm push, va += sizeof(argument) 
    // we just pushed [3, 2, 1] in our example 
    __asm { 
    lea eax, [new_format] 
    push eax 
    call printf 
    add esp,18h // <-- We now have to discard more stuff on the stack 
    } 
} 

请注意,您必须提前知道有多少参数是堆栈和每个参数的大小上(printf的计算本格式字符串)。

您可以模拟printf并从格式字符串(或您打包的任何其他函数)中提取相关信息。现在

,如果你没有对任何类型的知识,你仍然可以通过堆栈的变量上腾出空间摆脱它 和复制内存(从堆栈):

__asm { 
    push extra2 
    push extra1 
    sub esp, total-bytes-needed 
} 
memcpy(esp, block-of-memory, size-of-block); 

这是相当麻烦,不便携的解决方案,但它应该工作。

希望有帮助!