gpt4 book ai didi

c - 实现可变参数检查自定义字符串格式化函数

转载 作者:太空宇宙 更新时间:2023-11-04 02:23:45 24 4
gpt4 key购买 nike

Visual Studio 2015 引入了两个新警告,C4473 和 C4477,当字符串格式设置函数的格式字符串与关联的可变参数不匹配时,它们会发出通知:

warning C4473: 'printf' : not enough arguments passed for format string
warning C4477: 'printf' : format string '%p' requires an argument of type 'void *', but variadic argument 1 has type 'int'

这些警告非常有用,其他流行的编译器(gcc 和 clang,我相信带有 -wformat 选项,尽管我对这些编译器不太熟悉)已经支持了一段时间.

现在我的问题是我想使用自定义 Log(format, ...) 函数来处理日志记录,这会做额外的工作(例如,写入文件和控制台,或添加时间戳)。

但为了这个问题,让我们假设我只是简单地包装对 printf 的调用:

void Log(const char * format, ...)
{
va_list args;
va_start(args, format);
printf(format, args);
va_end(args);
}

通过这样做,如果我使用不匹配的参数调用我的 Log 函数,我就不会在上面显示警告:

printf("Error: %p\n", 'a'); // warning C4477
printf("Error: %p\n"); // warning C4473
Log("Error: %p\n", 'a'); // no warning
Log("Error: %p\n"); // no warning

有没有办法告诉编译器它应该检查我的函数的可变参数,就像检查 printf 一样?特别是对于 MSVC 编译器,但适用于 gcc 和 clang 的解决方案也将受到赞赏。

最佳答案

我不知道 VS 2015 或 VS 2017 中有什么可用(在 Microsoft documentation 的半随意搜索未提供任何说明)。但是,GCC 和 Clang 都支持声明式 function attribute :

__attribute__((format(printf(,n,m)))

可以像这样将其分解为合理的可移植代码:

#if !defined(PRINTFLIKE)
#if defined(__GNUC__)
#define PRINTFLIKE(n,m) __attribute__((format(printf,n,m)))
#else
#define PRINTFLIKE(n,m) /* If only */
#endif /* __GNUC__ */
#endif /* PRINTFLIKE */



extern NORETURN void err_abort(const char *format, ...) PRINTFLIKE(1,2);
extern NORETURN void err_error(const char *format, ...) PRINTFLIKE(1,2);



extern void err_logmsg(FILE *fp, int flags, int estat, const char *format, ...) PRINTFLIKE(4,5);

extern void err_remark(const char *format, ...) PRINTFLIKE(1,2);

PRINTFLIKE(n,m) 宏表示 printf() 格式字符串是参数 n,实际参数从。其中大部分类似于 printf(),格式字符串作为第一个参数,数据紧随其后。 err_logmsg() 函数在参数 4 的格式字符串之前有更多的控制选项,但是格式参数从 5 开始,紧接着,有点像 fprintf() 有它的格式字符串作为参数 2,参数从参数 3 开始。

设计一个参数介于格式字符串和可变参数列表之间的函数是可行的,例如:

extern NORETURN void err_pos_error(const char *format, const char *filename, int lineno, const char *function, ...) PRINTFLIKE(1,5);

可以这样调用:

err_pos_error("Failed to open file '%s': %d - %s\n", __FILE__, __LINE__, __func__, filename, errno, strerror(errno));

我们可以讨论这是否是一个好的设计(最好将 __FILE____LINE____func__ 参数放在format string, not after, for a variety reasons),但它是一个可行的设计,它在 PRINTFLIKE 宏中演示了非连续数字 — 或者使用 __attribute__((format(printf, n,m))).

NORETURN 是用于识别不返回函数的宏支持:

#if !defined(NORETURN)
#if __STDC_VERSION__ >= 201112L
#define NORETURN _Noreturn
#elif defined(__GNUC__)
#define NORETURN __attribute__((noreturn))
#else
#define NORETURN /* If only */
#endif /* __STDC_VERSION__ || __GNUC__ */
#endif /* NORETURN */

我所基于的代码在我的 SOQ 中可用。 (堆栈溢出问题)GitHub 上的存储库作为文件 stderr.cstderr.hsrc/libsoq子目录。

关于c - 实现可变参数检查自定义字符串格式化函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54032577/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com