Ich habe eine Datei test.cpp, die so aussieht:
%Vor% Das Kompilieren in 64-Bit-GCC mit dem -Wsign-conversion
-Flag erzeugt die Warnung:
(Zeile 2 ist die Zeile, in der new
aufgerufen wird). Es erscheint mir merkwürdig, dass GCC diese Warnung über das Zuweisen eines Arrays geben sollte, aber die folgenden Dinge sind noch seltsamer:
unsigned char *a=new unsigned char[(long unsigned int)n];
wird die Warnung weder entfernt noch wird static_cast<long unsigned int>()
. Es wird keine Warnung ausgegeben, wenn f
mit der Signatur void f(T n)
definiert ist, wobei T
Es werden jedoch Warnungen ausgegeben, wenn T
ein Constored-Integer-Typ ist, der kleiner als 64 Bits ist.
Wenn ich bedenke, dass ich auf einer 64-Bit-Maschine (Linux) arbeite, warum kümmert sich die Signierungskonvertierungswarnung in diesem Fall um die Konstanz und Größe von n
, und warum gibt Casting nicht den Fehler Problem?
Hinweis 1: Ich wollte dies unter einem anderen Compiler testen, aber die Comeau-Site ist nicht erreichbar, und ich habe keinen Zugriff auf andere Compiler, daher kann ich nicht sagen, ob dies standardkonformes Verhalten ist oder ein GCC-Fehler.
Hinweis 2: test.cpp ist ein minimales Beispiel für ein Problem von einer "echten" C ++ - Datei, in der ich die Warnung am besten mit der folgenden Zeile umgehen konnte:
%Vor%Ich bin ein wenig flockig auf die Details, aber es scheint mir, dass das Problem tatsächlich in der Zeichenerweiterung ist (da size_t höchstwahrscheinlich eine nicht signierte Länge auf Ihrem System ist). Betrachten Sie den folgenden Code:
%Vor%es druckt:
%Vor%Beachten Sie, dass ich absichtlich einen Wert gewählt habe, der ein Negativ als int, aber nicht als lang bedeutet. Der erste Druck sollte eigentlich 0x0000000080000000 sein. Wenn ich eine einfache -1 auswählen würde, würde sie immer noch vorzeichenerweitert als eine -1, aber diese gibt etwas völlig anderes.
Natürlich, wenn Sie es explizit auf unsigned umwandeln, erhalten Sie auch etwas anderes, aber ich schätze, dass der Compiler eher besorgt ist über die impliziten Konvertierungen (die Up-Conversion auf 64 Bit in diesem Fall), die Sie eher haben zu vermissen ("was könnte möglicherweise mit mehr Bits schief gehen?")
Noch ein Hinweis, dass es der Upconvert ist, der uns nervt (wenn nicht, werde ich mich freuen, eine andere Erklärung zu hören):
%Vor%Dies beschwert sich nur auf b
%Vor%Wir haben also ausgeschlossen, dass die Übergabe von Funktionsargumenten Schuld ist
Nun, wenn ich weiter spekulieren kann, ist diese Warnung vielleicht spezifisch für Speicherzuweisungen (beachten Sie, dass Sie es nicht durch einfaches Umwandeln von n zu long erhalten), weil der Compiler eine Zuweisungsmagie für eine Konstante ausgegeben hätte Größe. Stellen Sie sich den Schock vor, als er gesehen hat, was Sie vorhaben.
const int ist ein vorzeichenbehafteter Wert. Sie übergeben einen vorzeichenbehafteten Wert an einen vorzeichenlosen Wert. Daher generiert der Compiler eine Warnung, dass diese Konvertierung in einigen Fällen zu falschen Berechnungen führen kann.
Nun, es konvertiert für Sie, aber es warnt Sie, dass die Umwandlung, die es macht, das Vorzeichen des Wertes ändern wird, sonst könnten Sie automatisch einen Wert verlieren und Bugs könnten es wiedersprechen, nur um zu sagen, dass Sie es sind Wird ein int in einen unsigned int umgewandelt, kann dies den Wert des Zeichens normal ändern, wenn ich int an den array bounds Operator übergeben habe, würde es nicht wie Sie es mögen.
Versuchen Sie, das Conversion-Flag zu aktivieren, das Sie aktiviert haben, und sehen Sie, ob dies immer noch das Flag ist, was die Warnung verursacht, weil es die Conversion-Funktion ist
Ich denke, das wird mit der Art und Weise zu tun haben, wie Integer-Literale behandelt werden: Wenn Sie
schreiben %Vor%Die Zahl zehn wird in eine vorzeichenbehaftete Ganzzahl konvertiert, und der Compiler sollte sich aus offensichtlichen Gründen niemals darüber beschweren. Also, ich denke, es wird eine Ausnahme bei der Typprüfung für die vorzeichenbehaftete Ganzzahl geben. Wenn Sie const int verwenden, scheint gcc dies als einen anderen Typ zu betrachten, für den die Integer-Ausnahme nicht gilt, daher die Warnung.
Das TL; DR: Wenn es die Größe von etwas darstellt, mach es zu einem std::size_t
.
Das Problem besteht darin, dass das Array new
als Größenparameter einen Wert vom Typ std::size_t
annimmt, der vom Standard als vorzeichenloser ganzzahliger Typ garantiert wird, wie die Compilerreklamation der Konvertierung in long unsigned int
belegt. Hier findet die Konvertierung mit Vorzeichen und ohne Vorzeichen statt und der (IMO) korrekte Weg, das Problem zu beheben, besteht darin, einfach den Parameter n
der Funktion f
type std::size_t
anzugeben. Dies unterdrückt die Warnung zumindest mit GCC 4.6 für x86_64 GNU / Linux.
Der Compiler warnt, weil sich das Zeichen bei der Konvertierung in einen vorzeichenlosen Wert ändern kann.
1. Ersetzen der fehlerhaften Zeile durch vorzeichenloses Zeichen * a = new unsigned char [(lang unsigned int) n]; löscht die Warnung nicht und verwendet auch nicht static_cast ().
Das Problem der Zeichenkonvertierung besteht weiterhin, Sie haben es nur explizit gemacht. Meine Vermutung ist, dass es immer noch nicht explizit genug ist, dass der Compiler Ihnen glaubt. Es glaubt immer noch, dass Sie aus irgendeinem Grund n
a signiert const int
deklariert haben!
2. Es wird keine Warnung erzeugt, wenn f mit der Signatur void f (T n) definiert ist, wobei T
ist1. jeder nicht konstante, vorzeichenbehaftete oder vorzeichenlose Integer beliebiger Größe
Wenn n
nicht konstant ist, könnte Code zwischen dem Anfang der Funktion und der Konvertierung sein, der sicherstellt, dass n positiv ist, wie n = (long unsigned int)(n);
. Es scheint, dass der Compiler Ihnen in diesem Fall den Vorteil des Zweifels gibt und deshalb nicht warnt. Wenn für const deklariert ist, weiß der Compiler sicher, dass es sich um ein int
handelt, und warnt.
Ich gebe zu, meine Erklärungen klingen nicht wie etwas, was g ++ normalerweise tun würde.
Das Problem liegt in der Signatur Ihrer Funktion - der Compiler würde eine implizite Konvertierung durchführen, wenn Sie das konstante Literal 4 an eine Funktion übergeben, deren entsprechendes Argument als const int deklariert ist .
Sie können versuchen, den Argumenttyp als const unsigned int zu ersetzen, um die Warnmeldung loszuwerden.