【发布时间】:2020-02-15 22:44:45
【问题描述】:
我想实现一个类似于 printf 的可变参数函数,除了它打印一些前缀。例如,假设我希望前缀是time(0) 的值。如果我打电话:
wrapped_printf("Hello, world %d", 5678);
我会期待这样的:
1571441246 Hello, world 5678
作为输出。
显然,替换格式字符串并不是什么大问题;给我带来麻烦的是可变参数业务。我应该将其实现为采用... 的函数吗?采取va_list?以及如何添加我的额外参数?
这就是我现在所拥有的。它可以编译并运行(它甚至是有效的 C89...),但是额外的参数会被弄乱。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <time.h>
int wrapped_printf(const char* format_str, ...)
{
static const char* const prefix = "%d ";
static const size_t prefix_length = 3;
va_list ap;
size_t format_string_length = strlen(format_str);
char* const prefixed_format_str = malloc(format_string_length + prefix_length + 2);
/* 1 for the trailing '\0' and 1 for a line break */
if (prefixed_format_str == NULL) { exit(EXIT_FAILURE); }
strncpy(prefixed_format_str, prefix, prefix_length);
strncpy(prefixed_format_str + prefix_length, format_str, format_string_length);
prefixed_format_str[prefix_length + format_string_length] = '\n';
prefixed_format_str[prefix_length + format_string_length + 1] = '\0';
va_start(ap, format_str);
return printf(
prefixed_format_str,
(int) time(0),
ap);
va_end(ap);
}
int main()
{
wrapped_printf("Hello world %d\n", 5678);
return EXIT_SUCCESS;
}
在 Coliru 上查看 failing。
注意事项:
- 只能一个调用 - 但它可以是
printf()或vprintf()。 - 可以使用一个大字符串缓冲区,将
sprintf()前缀放入其中,然后sprintf()将原始参数放在后面;但这也不是我的意思。 - 我不介意使用特定于编译器的代码 - 但如果您建议这样做,请尝试在多个平台上覆盖多个编译器 - 特别是 GCC 或带有 AMD64 处理器的 GNU/Linux 上的 clang。
【问题讨论】:
标签: c printf variadic-functions