C++ 为错误使用自定义 print/log 函数添加编译器警告

C++ Add compiler warnings for wrong usage of custom print/log function

我有以下功能,我想像使用 printf 时那样收到警告:

void LoggingManager::log(int32_t logLevel, const char *p_str, ...)
{
    va_list args;
    va_start(args, p_str);
    vsnprintf(s_LogginManagerBuffer, LOGGING_MANAGER_BUFFER_SIZE - 1, p_str, args);
    va_end(args);

    internalLog(s_LogginManagerBuffer);
}

如果我忘记为格式字符串中的标记之一添加参数,我想以某种方式收到警告。对于有太多(或错误的参数)的警告也会很棒。 由于忘记了日志记录函数中的参数,我最近遇到了一些崩溃。

如果不能这样做,我该如何重写我的函数,使其具有警告但功能相同?

如果您使用 gcc/g++/clang,您可以使用 format 属性,如 this page:

中指定

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

The format attribute specifies that a function takes printf, scanf, strftime or strfmon style arguments that 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.

__attribute__在函数原型之前还是之后都没有关系。

所以在你的情况下你可以这样做:

class LoggingManager {
    ...
public:
    void log(int32_t logLevel, const char *p_str, ...) __attribute__((format (printf, 3, 4)));
    ...
};

请注意,因为这是一个成员函数,所以您需要考虑传递的隐式 this 参数。所以格式字符串实际上是第三个参数而不是第二个。 (format (printf, 3, 4) 而不是 format (printf, 2, 3)

看到效果了 here

如果你正在使用 Visual Studio 你可以使用 SAL annotation _Printf_format_string_ 宏:

#include <sal.h>

void log
(
    int32_t                                    log_level
,   _In_z_ _Printf_format_string_ const char * psz_format
,   ...
);

为了使代码可移植,您可能需要在必要时定义格式属性宏和 SAL 宏替换:

#if defined(__GNUC__)
#define ATTRIBUTE_PRINTF(format_index, vargs_index) __attribute__((__format__ (__printf__, format_index, vargs_index)))
#else
#define ATTRIBUTE_PRINTF(format_index, vargs_index)
#endif

#if defined(_MSC_VER)
#include <sal.h>
#else
#define _In_z_
#define _Printf_format_string_
#endif

void log
(
    int32_t                                    log_level
,   _In_z_ _Printf_format_string_ const char * psz_format
,   ...
) ATTRIBUTE_PRINTF(2, 3);