2016-04-04 4 views
2

Es ist sehr üblich, dass ein mittelgroßes Projekt printf durch eine benutzerdefinierte Protokollfunktion ersetzt. Hier ist eine minimal C++ Beispiel und seine Nutzung:Fehlender Fehler beim Übergeben der Zeichenfolge an die Protokollfunktion "printf-style"

#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 
} 

Die einfache Logger erhält eine variable Menge von Argumenten und ruft vprintf zu deren Ausgabe auf die Standardausgabe. Die Zeilen unter "korrekter Code" zeigen die korrekte Verwendung dieses Loggers. Meine Frage betrifft die "schlechten" Zeilen, in denen ein String-Objekt anstelle eines Zeigers zum Zeichenpuffer falsch übergeben wird.

Unter GCC 4.6 (getestet unter Linux) kann keine der schlechten Zeilen kompiliert werden, was eine gute Sache ist, da ich solche falsche Nutzung abfangen möchte. Der Fehler ist:

error: cannot pass objects of non-trivially-copyable type ‘std::string {aka struct std::basic_string<char>}’ through ‘...’ 

jedoch in GCC 5.1 es offenbar geworden ist möglich, nicht-trivialer kopierbar Objekte zu passieren, und die Kompilierung erfolgreich ist. Wenn ich -Wall, dann nur 'schlechte Zeile 1' eine Warnung über einen unerwarteten Argumenttyp, aber 'schlechte Zeile 2' mit dem Log_printf kompiliert in jedem Fall ohne Problem. Unnötig zu erwähnen, dass beide Linien eine Müllausgabe erzeugen.

Ich kann 'schlechte Linie 1' mit -Wall -Werror fangen, aber was ist mit 'schlechte Linie 2'? Wie kann ich auch einen Kompilierungsfehler erzeugen?

Antwort

2

Für Ihre eigenen Funktionen benötigen Sie einen common function attribute Aufruf verwenden format:

void log_printf(const char* fmt, ...) __attribute__((format (printf, 1, 2))); 

void log_printf(const char* fmt, ...) { 
    ... 
} 

Beachten Sie, dass das Attribut auf eine Funktion Erklärung eingestellt werden muss, nicht die Definition.

Das erste Argument für das format Attribut der Stil ist, in diesem Fall printf (scanf ist auch möglich, für Funktionen, die wie scanf funktionieren), ist das zweite Argument das Format-String, und das dritte Argument ist, wo die Auslassungs ... ist. Es wird GCC helfen, die Formatzeichenfolgen wie für die Standardfunktion printf zu überprüfen.

Dies ist eine GCC-Erweiterung, obwohl einige andere Compiler es übernommen haben, GCC-kompatibel zu werden, vor allem der Intel C-Compiler ICC und Clang (der Standard-Compiler für OSX und einige BSD-Varianten). Der Visual Studio-Compiler hat diese Erweiterung nicht, und ich kenne keine ähnliche Sache für Visual C++.

+0

Funktioniert immer noch nicht für mich. https://godbolt.org/g/3KKhwX – Jts

+0

@ José Sie meinen, es zeigt die Warnungen nicht? Versuchen Sie es in einem Nicht-Online-Compiler und Sie werden sie sehen. Weder das noch Ideone scheint Warnungen zu geben. –

Verwandte Themen