在C中,是否有可能转发可变函数的调用?如,
int my_printf(char *fmt, ...) {
fprintf(stderr, "Calling printf with fmt %s", fmt);
return SOMEHOW_INVOKE_LIBC_PRINTF;
}
在这种情况下,以上述方式转发调用显然不是严格必要的(因为您可以以其他方式记录调用,或使用vfprintf),但我正在处理的代码库要求包装器做一些实际工作,并且没有(也不可能添加)类似于vfprintf的帮助函数。
[更新:根据目前提供的答案,似乎有一些困惑。用另一种方式来表达这个问题:一般来说,你可以在不修改函数定义的情况下包装任意的变进函数吗?
如果可以使用c++ 11或更高版本的编译器编译代码,则可以使用可变参数函数模板:
#include <stdio.h>
template<typename... Targs>
int my_printf(const char *fmt, Targs... Fargs) {
fprintf(stderr, "Calling printf with fmt %s", fmt);
return printf(fmt, Fargs...);;
}
int main() {
my_printf("test %d\n", 1);
return 0;
}
Demo
GCC提供了一个可以做到这一点的扩展:__builtin_apply和relatives。参见gcc手册中的构造函数调用。
一个例子:
#include <stdio.h>
int my_printf(const char *fmt, ...) {
void *args = __builtin_apply_args();
printf("Hello there! Format string is %s\n", fmt);
void *ret = __builtin_apply((void (*)())printf, args, 1000);
__builtin_return(ret);
}
int main(void) {
my_printf("%d %f %s\n", -37, 3.1415, "spam");
return 0;
}
戴上试试吧
文档中有一些警告,说明它可能不适用于更复杂的情况。你必须硬编码参数的最大大小(这里我使用了1000)。但它可能是其他涉及用C或汇编语言分析堆栈的方法的合理替代方案。
不是直接的,但是变进函数与可变参数样式的替代函数成对出现是很常见的(在标准库中几乎是普遍的情况)。例如printf函数/
v……函数接受一个va_list形参,它的实现通常是通过编译器特定的“宏魔法”来完成的,但是你可以保证调用v…像这样的可变函数的样式函数可以工作:
#include <stdarg.h>
int m_printf(char *fmt, ...)
{
int ret;
/* Declare a va_list type variable */
va_list myargs;
/* Initialise the va_list variable with the ... after fmt */
va_start(myargs, fmt);
/* Forward the '...' to vprintf */
ret = vprintf(fmt, myargs);
/* Clean up the va_list */
va_end(myargs);
return ret;
}
这应该会给你你正在寻找的效果。
如果你正在考虑编写一个可变值库函数,你还应该考虑将一个va_list样式的同伴作为库的一部分。从你的问题中可以看出,它对你的用户是有用的。
Not sure if this helps to answer OP's question since I do not know why the restriction for using a helper function akin to vfprintf in the wrapper function applies. I think the key problem here is that forwarding the variadic argument list without interpreting them is difficult. What is possible, is to perform the formatting (using a helper function akin to vfprintf: vsnprintf) and forward the formatted output to the wrapped function with variadic arguments (i.e. not modifying the definition of the wrapped function). So, here we go:
#include <stdio.h>
#include <stdarg.h>
int my_printf(char *fmt, ...)
{
if (fmt == NULL) {
/* Invalid format pointer */
return -1;
} else {
va_list args;
int len;
/* Initialize a variable argument list */
va_start(args, fmt);
/* Get length of format including arguments */
len = vsnprintf(NULL, 0, fmt, args);
/* End using variable argument list */
va_end(args);
if (len < 0) {
/* vsnprintf failed */
return -1;
} else {
/* Declare a character buffer for the formatted string */
char formatted[len + 1];
/* Initialize a variable argument list */
va_start(args, fmt);
/* Write the formatted output */
vsnprintf(formatted, sizeof(formatted), fmt, args);
/* End using variable argument list */
va_end(args);
/* Call the wrapped function using the formatted output and return */
fprintf(stderr, "Calling printf with fmt %s", fmt);
return printf("%s", formatted);
}
}
}
int main()
{
/* Expected output: Test
* Expected error: Calling printf with fmt Test
*/
my_printf("Test\n");
//printf("Test\n");
/* Expected output: Test
* Expected error: Calling printf with fmt %s
*/
my_printf("%s\n", "Test");
//printf("%s\n", "Test");
/* Expected output: %s
* Expected error: Calling printf with fmt %s
*/
my_printf("%s\n", "%s");
//printf("%s\n", "%s");
return 0;
}
我遇到了这个解。
编辑:修正由egmont指出的错误