2010-09-07 7 views
49

Ich arbeite derzeit durch Accelerated C++ und habe ein Problem in Übung 2-3 gestoßen.Eine Warnung - Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen Integer-Ausdrücken

Ein schneller Überblick über das Programm - das Programm im Grunde nimmt einen Namen, dann zeigt eine Begrüßung in einem Rahmen von Sternchen - d. H. Hallo! umgeben von * s umgeben.

Die Übung - In dem Beispielprogramm verwenden die Autoren const int, um die Auffüllung (Leerzeichen) zwischen der Begrüßung und den Sternchen zu bestimmen. Sie bitten dann den Leser, als Teil der Übung den Benutzer nach der Eingabe zu fragen, wie groß die Füllung sein soll.

All dies einfach genug scheint, gehe ich frage vor dem Benutzer für zwei ganze Zahlen (int) und speichert sie und das Programm ändern, um diese Zahlen zu verwenden, die, die vom Autor selbst benutzt zu entfernen, beim Kompilieren obwohl ich die folgende Warnung ;

Exercise2-3.cpp: 46: Warnung: Vergleich zwischen mit und ohne Vorzeichen integer Ausdrücke

Nach einigen Recherchen scheint es zu sein, weil der Code eine der oben genannten Zahlen zu vergleichen versucht (int) zu einem string::size_type, was in Ordnung ist. Aber ich frage mich - bedeutet das, ich sollte eine der ganzen Zahlen zu unsigned int ändern? Ist es wichtig, explizit anzugeben, ob meine Ganzzahlen signiert oder nicht signiert sind?

cout << "Please enter the size of the frame between top and bottom you would like "; 
int padtopbottom; 
cin >> padtopbottom; 

cout << "Please enter size of the frame from each side you would like: "; 
unsigned int padsides; 
cin >> padsides; 

string::size_type c = 0; // definition of c in the program 
if (r == padtopbottom + 1 && c == padsides + 1) { // where the error occurs 

über den entsprechenden Bits des Codes ist, ist die c vom Typ string::size_type, weil wir nicht wissen, wie lange die Begrüßung sein könnte - aber warum, kann ich dieses Problem jetzt erhalten, wenn der Code des Autors nicht bekommen das Problem bei der Verwendung const int? Zusätzlich - zu jedem, der Accelerated C++ abgeschlossen haben kann - wird das später im Buch erklärt?

Ich bin auf Linux Mint mit g ++ über Geany, wenn das hilft oder einen Unterschied macht (wie ich gelesen habe, könnte es bei der Bestimmung, was string::size_type ist).

+2

würde nicht annehmen, dass Sie ein in unsigned ints sowieso wollen würde? Ich kann mir keinen logischen Grund vorstellen, warum die Ober- und Unterseite negativ sein sollte – Woot4Moo

+0

Das ist wahr und ich erwähnte das oben im Beitrag, aber ich verstehe immer noch nicht, warum dieses Problem nicht im Beispielprogramm des Autors auftrat sie benutzten const int?Ich bin mir sicher, dass ich dazu im Buch komme, aber ich kann nicht helfen, neugierig zu sein. –

+0

Scrap das - offensichtlich gab es keine Warnung in dieser Situation, weil der Int wurde immer 1 ... oops sein. –

Antwort

65

Es ist normalerweise eine gute Idee, Variablen wie unsigned oder size_t zu deklarieren, wenn sie mit Größen verglichen werden, um dieses Problem zu vermeiden. Verwenden Sie nach Möglichkeit den genauen Typ, mit dem Sie vergleichen werden (verwenden Sie zum Beispiel std::string::size_type im Vergleich mit einer std::string Länge).

Compiler warnen davor, signierte und unsignierte Typen zu vergleichen, da die Bereiche von signierten und unsignierten Ints unterschiedlich sind, und wenn sie miteinander verglichen werden, können die Ergebnisse überraschend sein. Wenn Sie einen solchen Vergleich durchführen müssen, sollten Sie einen der Werte explizit in einen Typ konvertieren, der mit dem anderen kompatibel ist, möglicherweise nach der Überprüfung, ob die Konvertierung gültig ist. Beispiel:

unsigned u = GetSomeUnsignedValue(); 
int i = GetSomeSignedValue(); 

if (i >= 0) 
{ 
    // i is nonnegative, so it is safe to cast to unsigned value 
    if ((unsigned)i >= u) 
     iIsGreaterThanOrEqualToU(); 
    else 
     iIsLessThanU(); 
} 
else 
{ 
    iIsNegative(); 
} 
+10

Ich weiß, dass der aktuelle C-Standard manchmal erfordert, dass negative vorzeichenbehaftete Werte größer als vorzeichenlose Werte sind, aber sollten Situationen, in denen dies auftritt, nicht als veraltet gelten? Ich würde gerne sehen, dass sich die Standards zu mindestens * erlauben * Compiler entwickeln, um arithmetisch korrektes Verhalten zu erzeugen (das heißt, wenn der vorzeichenbehaftete Wert negativ ist, vergleicht er kleiner, und wenn der vorzeichenlose Wert den maximalen Wert des signierten Typs überschreitet vergleicht größer). Es erscheint merkwürdig, dass Compiler in Abwesenheit expliziter Typcasts ein doofes Verhalten erzeugen müssen. – supercat

+3

@supercat: Da Integer-Vergleiche auf einen einzelnen Maschinenbefehl kompiliert werden und jede Test- oder Edge-Case-Behandlung mehrere Maschinenbefehle benötigt, wird das, was Sie vorschlagen, wahrscheinlich nicht als C-Feature hinzugefügt das Standardverhalten, da dies die Leistung unnötig zunichte machen würde, selbst wenn der Programmierer weiß, dass es nicht notwendig ist. –

+0

@BlakeMiller: Code, der einen vorzeichenbehafteten und einen vorzeichenlosen Wert vergleichen möchte, so als ob beide vorzeichenlos sind, könnte einen Code erzeugen und "volle Geschwindigkeit" ausführen. Ansonsten würde in vielen Fällen der Unterschied zwischen einem Vergleich und einem Sprung bestehen, der zwei Anweisungen gegenüber drei nimmt, was billiger wäre als ein Code, der die verschiedenen Fälle manuell behandelt. – supercat

4

In den extremen Bereichen kann ein vorzeichenloser int größer als ein int werden.
Daher generiert der Compiler eine Warnung. Wenn Sie sicher sind, dass dies kein Problem ist, können Sie die Typen auf denselben Typ umwandeln, sodass die Warnung verschwindet (verwenden Sie C++ - Zeichen, damit sie leicht zu erkennen sind).

Alternativ können Sie die Variablen vom selben Typ machen, um zu verhindern, dass der Compiler sich beschwert.
Ich meine, ist es möglich, eine negative Polsterung zu haben? Wenn ja, dann behalte es als int. Andernfalls sollten Sie wahrscheinlich unsigned int verwenden und den Stream die Situationen erfassen lassen, in denen der Benutzer eine negative Zahl eingibt.

4

Der wichtige Unterschied zwischen vorzeichenbehafteten und vorzeichenlosen Ints ist die Interpretation des letzten Bits. Das letzte Bit in signierten Typen das Vorzeichen der Zahl darstellen, was bedeutet: zB:

0001 1 mit und ohne Vorzeichen 1001 -1 unterzeichnet und 9 unsigned

(vermied ich das ganze Komplement Problem für Klarheit der Erklärung! Dies ist nicht genau, wie Ints im Speicher dargestellt werden!)

Sie können sich vorstellen, dass es einen Unterschied macht, wenn Sie mit -1 oder mit +9 vergleichen. In vielen Fällen sind Programmierer einfach zu faul zu zählen Ints als unsigned deklarieren (Blähung der for-Schleife Kopf f.i) Es ist in der Regel kein Problem, weil mit ints Sie bis 2^31 zählen müssen, bis Ihr Zeichen Bit Sie beißt. Deshalb ist es nur eine Warnung. Weil wir zu faul sind, 'unsigned' statt 'int' zu schreiben.

+0

Ah ich sehe - ich habe jetzt die Zählung int als unsigned geändert. Wird dies als gute oder schlechte Praxis angesehen? :) –

+0

Bitte, wenn Sie Downvote, kurz erklären, warum. Auch wenn es nur ein Wort ist. Ich kann nichts falsch mit meiner Antwort sehen. Was könnte ein Problem sein, mit dem Sie mir helfen können. – AndreasT

+1

@Tim: "unsigned" ist ein Synonym für "unsigned int". Sie sollten unsigned int oder den STL-Standard-Zähl-/Iterationsvariablentyp std :: size_t verwenden (der ebenfalls ein Synonym ist). Es ist eine bewährte Methode, in allen Fällen von "iterieren über Elemente 0 bis n" ohne Vorzeichen zu verwenden. Es verbessert die Übersichtlichkeit und entfernt Warnungen, so dass es ein Gewinner ist ;-) – AndreasT

6

Ich hatte genau das gleiche Problem gestern Arbeit durch Problem 2-3 in Accelerated C++. Der Schlüssel besteht darin, alle Variablen, die Sie vergleichen (mit booleschen Operatoren), mit kompatiblen Typen zu ändern. In diesem Fall bedeutet das string::size_type (oder unsigned int, aber da dieses Beispiel das erstere verwendet, werde ich einfach dabei bleiben, obwohl die beiden technisch kompatibel sind).

Beachten Sie, dass sie in ihrem ursprünglichen Code genau das für den c-Zähler (Seite 30 in Abschnitt 2.5 des Buches) getan haben, wie Sie richtig hingewiesen haben.

Was dieses Beispiel komplizierter macht, ist, dass die verschiedenen Polstergrößen (padsides und padtopbottom) sowie alle Zähler müssen auch string::size_type geändert werden.

zu Ihrem Beispiel Erste, der Code, den Sie auf dem Laufenden würde am Ende wie folgt suchen:

cout << "Please enter the size of the frame between top and bottom"; 
string::size_type padtopbottom; 
cin >> padtopbottom; 

cout << "Please enter size of the frame from each side you would like: "; 
string::size_type padsides; 
cin >> padsides; 

string::size_type c = 0; // definition of c in the program 

if (r == padtopbottom + 1 && c == padsides + 1) { // where the error no longer occurs 

Beachten Sie, dass in der vorherigen bedingten, würden Sie die Fehlermeldung erhalten, wenn Sie nicht Variable r als initialisiert wurde string::size_type in der for Schleife. So müssen Sie die for-Schleife initialisieren mit so etwas wie:

for (string::size_type r=0; r!=rows; ++r) //If r and rows are string::size_type, no error! 

Also, im Grunde, wenn Sie eine string::size_type Variable in die Mischung einzuführen, immer wenn Sie einen Booleschen Operation an diesem Element ausgeführt werden soll, werden alle Operanden müssen ein kompatibler Typ für die Kompilierung ohne Warnungen.

0

oder this header library verwenden und schreiben:

// |notEqaul|less|lessEqual|greater|greaterEqual 
if(sweet::equal(valueA,valueB)) 

und kümmern sich nicht um mit/ohne Vorzeichen oder unterschiedliche Größen

Verwandte Themen