Warum warnt der 64-Bit-GCC davor, bei der Zuweisung eines Arrays einen const int in einen langen, unsigned int zu konvertieren?

8

Ich habe eine Datei test.cpp, die so aussieht:

%Vor%

Das Kompilieren in 64-Bit-GCC mit dem -Wsign-conversion -Flag erzeugt die Warnung:

%Vor%

(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:

  1. Durch Ersetzen der problematischen Zeile durch unsigned char *a=new unsigned char[(long unsigned int)n]; wird die Warnung weder entfernt noch wird static_cast<long unsigned int>() .
  2. verwendet
  3. Es wird keine Warnung ausgegeben, wenn f mit der Signatur void f(T n) definiert ist, wobei T

    ist
    1. jeder nicht konstante, vorzeichenbehaftete oder vorzeichenlose Integer beliebiger Größe oder
    2. ein vorzeichenbehafteter 64-Bit-Integer-Typ.

    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%     
Ose 09.04.2013, 15:31
quelle

7 Antworten

1

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.

    
Leeor 11.08.2013 13:54
quelle
0

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.

    
suhastheju 09.04.2013 16:24
quelle
0

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

    
Mohammed Hussain Arif 03.05.2013 03:42
quelle
0

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.

    
cmaster 15.06.2013 08:45
quelle
0

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.

    
Stuart Olsen 24.06.2013 17:52
quelle
0

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

ist      
    

1. 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.

    
nkaleidoskop 03.07.2013 08:37
quelle
0

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.

    
Fei 11.08.2013 05:54
quelle

Tags und Links