2016-06-10 6 views
3

Ich bin dabei, Compilerwarnungen in einem vererbten Projekt zu reparieren, das ich geerbt habe. Neuer Compiler ist gcc Version 4.8.5 20150623 (Red Hat 4.8.5-4) (GCC).C++ printf Feldbreite Specifier '. *' Erwartet int nicht size_t

Ihr ist viel Code wie folgt aus:

#include <cstdio> 
#include <cstring> 

struct foobar 
{ 
    char field1[10]; 
    char field2[5]; 
}; 

int main() 
{ 
    struct foobar foo; 
    memset(&foo, ' ', sizeof(foo)); 
    strncpy(foo.field1, "1234567890", sizeof(foo.field1)); 

    // Produces warning 
    printf("[%.*s]", sizeof(foo.field1), foo.field1); 

    return 0; 
} 

dies eine Warnung Meldungen erzeugt: ‚*‘

1_test.c: In function ‘int main()’: 
1_test.c:16:49: warning: field precision specifier ‘.*’ expects argument of type ‘int’, but argument 2 has type ‘long unsigned int’ [-Wformat=] 
    printf("[%.*s]", sizeof(foo.field1), foo.field1); 

Dies scheint falsch zu mir wie ein size_t erwarten sollte, aber anscheinend es nicht ...

Gibt es trotzdem, um dieses Problem global zu beheben, abgesehen davon, dass etwas wie folgt zu tun ist:

// Fixes 
    printf("[%.10s]", foo.field1); 

    // Fixes 
    printf("[%.*s]", static_cast<int>(sizeof(foo.field1)), foo.field1); 
+0

zu verwenden Ich wollte gerade sagen "verwenden' static_cast' ", aber Sie haben Recht, das ist eine hässliche Lösung. –

+0

printf ist nicht C++ – Slava

+1

@Slava Es ist nicht C++, aber es ist ein Teil davon – KABoissonneault

Antwort

0

Sie haben immer die Unfun aber manchmal die beste Lösung in einem Makro

#define INT_SIZEOF(x) static_cast<int>(sizeof((x))) 

printf("[%.*s]", INT_SIZEOF(foo.field1), foo.field1); 

einzuwickeln Wenn Ihr Code-Basis zu Makros allergisch ist, können Sie diese

eine einfache syntaktische Wrapper für die static_cast, wie tun kann
int AsInt(size_t n) { return static_cast<int>(n) } 
printf("[%.*s]", AsInt(sizeof(foo.field1)), foo.field1); 

Wie in den Kommentaren erläutert, kann diese Lösung nur einen Größenwert annehmen und erfordert daher einen separaten Operator sizeof. Außerdem verlieren Sie jede Chance bei einer Kompilierungsfehlerprüfung, wenn sizeof keinen Wert zurückgibt, der in eine Ganzzahl passt (sehr unwahrscheinlich).

Beachten Sie, dass Ihr Code in beiden Fällen immer noch hässlich ist, aber mindestens einer ist kürzer und benachrichtigt den Leser, dass etwas Hässliches vor sich geht.

Endlich eine weitere mögliche gute Alternative.

// constexpr is optional, you simply won't be able to use it in as many places if you don't use it 
template<typename T> constexpr int intSizeof(T = T{} /*replace with() if necessary*/) 
{ 
    return static_cast<int>(sizeof(T)); 
} 

printf("[%.*s]", intSizeof<decltype(foo.field1)>(), foo.field1); 

Diese Lösung ist auf jeden Fall mehr C++ und modernere, ohne real Kosten

+0

Wie wäre das jemals die "beste Lösung"? Was macht ein Makro, das eine Funktion nicht könnte? –

+0

@CodyGray Auswerten zur Kompilierzeit. Außerdem kann das Makro sowohl Typen als auch Ausdrücke annehmen, während eine Funktion oder ein Typ-Attribut nur eine davon annehmen kann. – KABoissonneault

+0

(Ja, Funktionen und typetraits können auch eine Kompilierung unter bestimmten Bedingungen bewerten) Wenn Sie einen Compiler verwenden, die von inlining eine Funktion nicht in der Lage ist, eine statische Besetzung und einen Operator sizeof enthält, dann sollten Sie im Grunde einfach aufgeben. Du verwendest das Makro nicht, um hier einen Typ zu übergeben, du verwendest es, um einen Wert zu übergeben, also sehe ich nicht, wie das funktioniert ...? –

2

Die richtige Lösung wäre:

std::cout << std::string(foo.field1, sizeof(foo.field1)); 

würde dies Ausgang, was Sie wünschen und keine Warnungen generieren. Aber bessere Lösung wäre natürlich std::string in struct foobar