如何将格式化的数据添加到printf()调用中

问题描述 投票:0回答:1

我想实现一个可变参数函数,其功能类似于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

注意:

  • one呼叫必须进行-但可以是printf()vprintf()
  • 一个人可以使用一个大的字符串缓冲区,将sprintf()作为前缀,然后使用sprintf()作为原始参数;但这也不是我的意思。
  • [我不介意使用特定于编译器的代码-但如果您建议这样做,请尝试在一个平台上涵盖多个编译器,尤其是GCC或带有AMD64处理器的GNU / Linux上的clang。
c printf variadic-functions
1个回答
1
投票

完全不可能在纯C中将[[prepend自变量移植到va_list中。完全可以确定,但是对于每个体系结构和compiler 电话会议

以一种可移植的方式,像libffi这样的库和一个用于格式字符串的解析器...


[我建议,如果您有幸参加C99 +,则建议您选择macro instead;那么您可以将"%d "放在带有编译时字符串分类的格式字符串前面,并轻松地在参数中添加数字。但是为此,格式必须是字符串文字。

或者,如果您确实需要使用函数,那么我不会受到限制,即不对后面跟着这些的前缀分别使用printf-

输出将是行缓冲的或全缓冲的,因此不会可能有任何区别。

#include <stdio.h> #include <stdlib.h> #include <string.h> #include <stdarg.h> #include <time.h> #define wrapped_printf_macro(f_, ...) \ printf("%lld " f_, (long long)time(0), __VA_ARGS__) int wrapped_printf(const char* format_str, ...) { static const char* const prefix = "%d "; static const size_t prefix_length = 3; va_list ap; printf("%lld ", (long long int)time(0)); va_start(ap, format_str); vprintf(format_str, ap); va_end(ap); } int main() { wrapped_printf_macro("Hello world %d\n", 5678); wrapped_printf("Hello world %d\n", 5678); return EXIT_SUCCESS; }

-1
投票
这就是我现在所拥有的。它可以编译并运行(甚至是有效的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
© www.soinside.com 2019 - 2024. All rights reserved.