中規模から大規模のプロジェクトでは、printf
をカスタムログ関数に置き換えるのが一般的です。ここでは、最小限のC++の例とその使用方法である:文字列をprintf形式のログ関数に間違って渡すとエラーが表示されない
#include <stdio.h>
#include <stdarg.h>
#include <string>
void log_printf(const char* fmt, ...) {
va_list ap;
va_start(ap, fmt);
vprintf(fmt, ap); // real code obviously does something fancier
va_end(ap);
}
int main() {
std::string x = "Hello";
// correct code
printf("String is %s\n", x.c_str());
log_printf("String is %s\n", x.c_str());
// incorrect code
printf("String is %s\n", x); // bad line 1
log_printf("String is %s\n", x); // bad line 2
}
シンプルなロガーは、引数の可変量を受信して、標準出力に出力するようにそれらをvprintf
を呼び出します。 「正しいコード」の下の行は、このロガーの正しい使い方を示しています。私の質問には文字バッファへのポインタの代わりに文字列オブジェクトが正しく渡される「悪い」行が含まれています。
GCC 4.6(Linuxでテスト済み)では、悪い行はコンパイルできません。このような誤った使い方をキャッチしたいので、これは良いことです。エラーは次のとおりです。
error: cannot pass objects of non-trivially-copyable type ‘std::string {aka struct std::basic_string<char>}’ through ‘...’
しかしGCC 5.1で、それは明らかに非自明-コピー可能オブジェクトを渡すことができるようになった、とコンパイルが成功します。私が-Wallを使用すると、 'bad line 1'だけが予期しない引数の型に関する警告を出しますが、log_printfで 'bad line 2'は問題なくコンパイルされます。言うまでもなく、両方の行がガベージ出力を生成します。
-Wall -Werror
で「悪い行1」を捕まえることができますが、「悪い行2」はどうですか?どうすればコンパイルエラーも発生させることができますか?属性が機能宣言、ない定義に設定しなければならないことを
void log_printf(const char* fmt, ...) __attribute__((format (printf, 1, 2)));
void log_printf(const char* fmt, ...) {
...
}
注:common function attributeコールformat
を使用する必要が独自の関数については
まだ動作しません。 https://godbolt.org/g/3KKhwX – Jts
@José警告が表示されないことを意味しますか?それを非オンラインコンパイラで試してみると、それらが表示されます。それも、イデオンも警告を表示していないようです。 –