2016-04-04 15 views
2

中規模から大規模のプロジェクトでは、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を使用する必要が独自の関数については

答えて

2

format属性の最初の引数は(scanfscanfように動作機能のためにも可能である)、この場合printfに、スタイルである、第二の引数は書式文字列であり、第3引数はここで省略符号であります...です。 GCCが標準のprintf機能のようなフォーマット文字列をチェックするのに役立ちます。

これはGCCの拡張機能ですが、他のコンパイラでもGCCと互換性があります。特にインテルCコンパイラICCとClang(OSXとBSDの亜種で使用される標準コンパイラ)です。 Visual Studioコンパイラにはこの拡張はありません。また、Visual C++には似たようなことは分かりません。

+0

まだ動作しません。 https://godbolt.org/g/3KKhwX – Jts

+0

@José警告が表示されないことを意味しますか?それを非オンラインコンパイラで試してみると、それらが表示されます。それも、イデオンも警告を表示していないようです。 –