如何在 C 中定义接受格式化输入字符串的函数?
How do I define a function that accepts a formatted input string in C?
我构建了一个接受“日志级别”和字符串的自定义日志记录函数。用户将指定与消息关联的日志级别(即错误、警告、跟踪等)。日志记录功能只会根据当前配置的日志级别将消息打印到控制台。
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);
有没有办法实现记录器功能,这样我就不需要让用户自己创建一个临时字符串?
这是question 15.5 on the C FAQ list。
你想要 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);
}
作为对@SteveSummit 回答的补充,许多编译器都有特殊的编译指示或属性来指示该函数是“类似 printf 的”。它允许编译器在编译时检查参数,就像使用 printf
时一样
示例 gcc :
format (archetype, string-index, first-to-check)
The format attribute specifies that a function takes printf, scanf,
strftime or strfmon style arguments which should be type-checked
against a format string. For example, the declaration:
extern int
my_printf (void *my_object, const char *my_format, ...)
__attribute__ ((format (printf, 2, 3)));
causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument
my_format.
The parameter archetype determines how the format string is interpreted, and should be printf, scanf, strftime or strfmon. (You
can also use __printf__
, __scanf__
, __strftime__
or __strfmon__
.) The
parameter string-index specifies which argument is the format string
argument (starting from 1), while first-to-check is the number of the
first argument to check against the format string. For functions where
the arguments are not available to be checked (such as vprintf),
specify the third parameter as zero. In this case the compiler only
checks the format string for consistency. For strftime formats, the
third parameter is required to be zero.
In the example above, the format string (my_format) is the second argument of the function my_print, and the arguments to check start
with the third argument, so the correct parameters for the format
attribute are 2 and 3.
The format attribute allows you to identify your own functions which take format strings as arguments, so that GCC can check the
calls to these functions for errors. The compiler always (unless
-ffreestanding is used) checks formats for the standard library functions printf, fprintf, sprintf, scanf, fscanf, sscanf, strftime,
vprintf, vfprintf and vsprintf whenever such warnings are requested
(using -Wformat), so there is no need to modify the header file
stdio.h. In C99 mode, the functions snprintf, vsnprintf, vscanf,
vfscanf and vsscanf are also checked. Except in strictly conforming C
standard modes, the X/Open function strfmon is also checked as are
printf_unlocked and fprintf_unlocked. See Options Controlling C
Dialect.
来源:https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html
我构建了一个接受“日志级别”和字符串的自定义日志记录函数。用户将指定与消息关联的日志级别(即错误、警告、跟踪等)。日志记录功能只会根据当前配置的日志级别将消息打印到控制台。
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);
有没有办法实现记录器功能,这样我就不需要让用户自己创建一个临时字符串?
这是question 15.5 on the C FAQ list。
你想要 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);
}
作为对@SteveSummit 回答的补充,许多编译器都有特殊的编译指示或属性来指示该函数是“类似 printf 的”。它允许编译器在编译时检查参数,就像使用 printf
示例 gcc :
format (archetype, string-index, first-to-check)
The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments which should be type-checked against a format string. For example, the declaration:
extern int my_printf (void *my_object, const char *my_format, ...) __attribute__ ((format (printf, 2, 3)));
causes the compiler to check the arguments in calls to my_printf for consistency with the printf style format string argument my_format. The parameter archetype determines how the format string is interpreted, and should be printf, scanf, strftime or strfmon. (You can also use
__printf__
,__scanf__
,__strftime__
or__strfmon__
.) The parameter string-index specifies which argument is the format string argument (starting from 1), while first-to-check is the number of the first argument to check against the format string. For functions where the arguments are not available to be checked (such as vprintf), specify the third parameter as zero. In this case the compiler only checks the format string for consistency. For strftime formats, the third parameter is required to be zero.In the example above, the format string (my_format) is the second argument of the function my_print, and the arguments to check start with the third argument, so the correct parameters for the format attribute are 2 and 3.
The format attribute allows you to identify your own functions which take format strings as arguments, so that GCC can check the calls to these functions for errors. The compiler always (unless -ffreestanding is used) checks formats for the standard library functions printf, fprintf, sprintf, scanf, fscanf, sscanf, strftime, vprintf, vfprintf and vsprintf whenever such warnings are requested (using -Wformat), so there is no need to modify the header file stdio.h. In C99 mode, the functions snprintf, vsnprintf, vscanf, vfscanf and vsscanf are also checked. Except in strictly conforming C standard modes, the X/Open function strfmon is also checked as are printf_unlocked and fprintf_unlocked. See Options Controlling C Dialect.
来源:https://gcc.gnu.org/onlinedocs/gcc-3.2/gcc/Function-Attributes.html