2017-08-11 17 views
3

我有以下功能,我想有警告視爲一個用printf當有:C++編譯器添加警告,自定義打印錯誤使用/日誌功能

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); 
} 

我想如果我忘記在格式字符串中爲其中一個標記添加參數,會出現警告。另外,有太多(或錯誤的參數)的警告會很棒。 由於忘記日誌功能中的參數,我最近面臨一些崩潰。

如果不可能這樣做,我怎麼能重寫我的功能,有警告但功能相同?

+2

請不要用c標記,這是無效的c代碼。 –

回答

4

如果您使用的GCC /克++ /鐺可以使用作爲this page指定的格式屬性:

格式(原型,字符串索引,第一 - 校驗)

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一致。

無論是__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

+0

請注意[Clang也支持這個](https://clang.llvm.org/docs/AttributeReference.html#format-gnu-格式)。 –

+0

@DanielH謝謝!更新了我的答案。 – Kevin

+0

謝謝!這是非常美麗的獎勵點,以向我展示如何在我的成員函數中使用它! :) – keyboard

0

如果您正在使用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);