3

我构建了一个自定义日志记录函数,该函数接受“日志级别”和字符串。用户将指定与消息关联的日志级别(即错误、警告、跟踪等)。日志功能只会根据配置的当前日志级别将消息打印到控制台。

int global_log_level = INFO;

void logger(int msg_log_level, char * msg)
{
    if(msg_log_level >= global_log_level )
    {
        printf("Log Level = %u: %s", msg_log_level, msg);
    }
}

理想情况下,我想将格式化的字符串提供给这个函数。

logger(LOG_LEVEL_ERROR, "Error of %u occurred\n", error_code);

但是,通过添加这种“包装”逻辑,我无法输入格式化的消息。相反,我必须将消息写入临时字符串,然后将其提供给函数。

char temp[512];
sprintf("Error of %u occurred\n", error_code);
logger(LOG_LEVEL_ERROR, temp);

有没有办法实现记录器功能,这样我就不需要让用户自己创建一个临时字符串?

4

2 回答 2

5

这是C FAQ 列表中的问题 15.5

你想要vprintf,它可以让你编写你自己的printf类似函数logger,但是你可以传递实际的格式字符串和参数vprintf来完成工作。诀窍是您需要构造一个特殊va_arg类型来“指向”可变长度参数列表。它看起来像这样:

#include <stdarg.h>

int global_log_level = INFO;

void logger(int msg_log_level, char * msg, ...)
{
    va_list argp;
    va_start(argp, msg);

    if(msg_log_level >= global_log_level )
    {
       printf("Log Level = %u: ", msg_log_level);
       vprintf(msg, argp);
    }

    va_end(argp);
}
于 2021-06-27T18:41:23.347 回答
1

作为@SteveSummit 答案的补充,许多编译器具有特殊的编译指示或属性来指示该函数是“类似printf”的。它允许编译器检查参数编译时与使用时所做的相同printf

示例 gcc:

format (archetype, string-index, first-to-check)

format 属性指定函数采用 printf、scanf、strftime 或 strfmon 样式参数,这些参数应根据格式字符串进行类型检查。例如,声明:

              extern int
              my_printf (void *my_object, const char *my_format, ...)
                    __attribute__ ((format (printf, 2, 3)));
              

导致编译器检查对 my_printf 的调用中的参数是否与 printf 样式格式字符串参数 my_format 保持一致。参数archetype 确定格式字符串的解释方式,应该是printf、scanf、strftime 或strfmon。(您也可以使用、 或__printf____scanf__)参数 string-index 指定哪个参数是格式字符串参数(从 1 开始),而 first-to-check 是要检查格式字符串的第一个参数的编号。对于无法检查参数的函数(例如 vprintf),将第三个参数指定为零。在这种情况下,编译器只检查格式字符串的一致性。对于 strftime 格式,第三个参数必须为零。__strftime____strfmon__

在上面的示例中,格式字符串 (my_format) 是函数 my_print 的第二个参数,要检查的参数从第三个参数开始,因此格式属性的正确参数是 2 和 3。

format 属性允许您识别自己的函数,这些函数将格式字符串作为参数,以便 GCC 可以检查对这些函数的调用是否有错误。编译器总是(除非使用 -ffreestanding)检查标准库函数 printf、fprintf、sprintf、scanf、fscanf、sscanf、strftime、vprintf、vfprintf 和 vsprintf 的格式,只要请求此类警告(使用 -Wformat),因此有无需修改头文件stdio.h。在 C99 模式下,还会检查函数 snprintf、vsnprintf、vscanf、vfscanf 和 vsscanf。除了严格符合 C 标准模式外,还检查 X/Open 函数 strfmon 以及 printf_unlocked 和 fprintf_unlocked。请参阅控制 C 方言的选项。

来源:https ://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html

于 2021-06-27T21:13:09.397 回答