Ich arbeite derzeit an Accelerated C ++ und bin in Übung 2-3 auf ein Problem gestoßen.
Ein kurzer Überblick über das Programm - das Programm nimmt im Grunde genommen einen Namen an und zeigt dann eine Begrüßung in einem Rahmen aus Sternchen an - dh Hallo! umgeben von * 's gerahmt.
Die Übung - Im Beispielprogramm const int
bestimmen die Autoren den Abstand (Leerzeichen) zwischen der Begrüßung und den Sternchen. Anschließend bitten sie den Leser im Rahmen der Übung, den Benutzer um Eingabe zu bitten, wie groß die Polsterung sein soll.
All dies scheint einfach zu sein. Ich frage den Benutzer nach zwei Ganzzahlen ( int
), speichere sie und ändere das Programm, um diese Ganzzahlen zu verwenden. Dabei entferne ich die vom Autor verwendeten Ganzzahlen, obwohl ich die folgende Warnung erhalte.
Übung 2-3.cpp: 46: Warnung: Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen ganzzahligen Ausdrücken
Nach einigen Recherchen scheint dies daran zu liegen, dass der Code versucht, eine der oben genannten Ganzzahlen ( int
) mit a zu vergleichen string::size_type
, was in Ordnung ist. Aber ich habe mich gefragt - bedeutet das, dass ich eine der ganzen Zahlen ändern sollte unsigned int
? 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
Oben sind die relevanten Codebits aufgeführt, die c
vom Typ sind, string::size_type
da wir nicht wissen, wie lange die Begrüßung dauern könnte - aber warum bekomme ich dieses Problem jetzt, wenn der Code des Autors das Problem bei der Verwendung nicht bekommen hat const int
? Wird dies später in diesem Buch erklärt - für alle, die möglicherweise Accelerated C ++ abgeschlossen haben ?
Ich bin auf Linux Mint und benutze 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).
quelle
unsigned
integraler Typen für Zählungen. Nicht signierte Nummern haben auch ein garantiertes Umlaufverhalten, wodurch sie geringfügig weniger effizient sind.Antworten:
Es ist in der Regel eine gute Idee zu erklären Variablen wie
unsigned
odersize_t
ob sie auf Größen verglichen werden, um dieses Problem zu vermeiden. Verwenden Sie nach Möglichkeit den genauen Typ, mit dem Sie vergleichen möchten (z. B.std::string::size_type
beim Vergleich mitstd::string
der Länge von a).Compiler geben Warnungen zum Vergleichen von vorzeichenbehafteten und vorzeichenlosen Typen aus, da die Bereiche für vorzeichenbehaftete und vorzeichenlose Ints unterschiedlich sind. 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 mit dem anderen kompatiblen Typ konvertieren, möglicherweise nachdem Sie überprüft haben, ob die Konvertierung gültig ist. Zum 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(); }
quelle
#include <cstdio>
oben ... und ich verwende g ++ 4.4.7) "true" aus und gibt an, dass es wahr ist, dass (signiert) -1 ist größer als (ohne Vorzeichen) 12:int main(int, char**) { int x = -1; unsigned int y = 12; printf("x > y: %s\n", x > y ? "true":"false"); return 0; }
Ich hatte gestern genau das gleiche Problem, als ich Problem 2-3 in Accelerated C ++ durcharbeitete. Der Schlüssel besteht darin, alle Variablen, die Sie vergleichen (unter Verwendung von Booleschen Operatoren), in kompatible Typen zu ändern. In diesem Fall bedeutet das
string::size_type
(oderunsigned int
, aber da in diesem Beispiel das erstere verwendet wird, bleibe ich einfach dabei, obwohl die beiden technisch kompatibel sind).Beachten Sie, dass sie in ihrem ursprünglichen Code genau dies für den c-Zähler getan haben (Seite 30 in Abschnitt 2.5 des Buches), wie Sie zu Recht betont haben.
Was dieses Beispiel komplizierter macht, ist, dass die verschiedenen Füllvariablen (Padsides und Padtopbottom) sowie alle Zähler ebenfalls geändert werden müssen
string::size_type
.Wenn Sie zu Ihrem Beispiel kommen, sieht der von Ihnen veröffentlichte Code folgendermaßen aus:
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 Sie in der vorherigen Bedingung den Fehler erhalten würden, wenn Sie die Variable r nicht als
string::size_type
in derfor
Schleife initialisieren würden . Sie müssen die for-Schleife also folgendermaßen initialisieren:for (string::size_type r=0; r!=rows; ++r) //If r and rows are string::size_type, no error!
Wenn Sie also eine
string::size_type
Variable in den Mix einfügen, müssen alle Operanden einen kompatiblen Typ haben, damit sie ohne Warnungen kompiliert werden können, wenn Sie eine boolesche Operation für dieses Element ausführen möchten.quelle
Der wichtige Unterschied zwischen vorzeichenbehafteten und vorzeichenlosen Ints ist die Interpretation des letzten Bits. Das letzte Bit in vorzeichenbehafteten Typen stellt das Vorzeichen der Zahl dar, dh: z.
0001 ist 1 signiert und nicht signiert 1001 ist -1 signiert und 9 nicht signiert
(Ich habe das gesamte Komplementproblem aus Gründen der Klarheit der Erklärung vermieden! So werden Ints nicht genau im Speicher dargestellt!)
Sie können sich vorstellen, dass es einen Unterschied macht, zu wissen, ob Sie mit -1 oder mit +9 vergleichen. In vielen Fällen sind Programmierer einfach zu faul, um das Zählen von Ints als vorzeichenlos zu deklarieren (Aufblähen des for-Loop-Head-Fi). Dies ist normalerweise kein Problem, da Sie bei Ints bis 2 ^ 31 zählen müssen, bis Ihr Vorzeichen Sie beißt. Deshalb ist es nur eine Warnung. Weil wir zu faul sind, um 'unsigned' anstelle von 'int' zu schreiben.
quelle
1001
für -1 war eine schlechte Wahl, eine viel bessere Wahl wäre "1111
gleich -1 signiert und 15 nicht signiert"In den extremen Bereichen kann ein vorzeichenloses int größer werden als ein int.
Daher generiert der Compiler eine Warnung. Wenn Sie sicher sind, dass dies kein Problem ist, können Sie die Typen in denselben Typ umwandeln, damit die Warnung verschwindet (verwenden Sie C ++ - Umwandlung, damit sie leicht zu erkennen sind).
Alternativ können Sie die Variablen auf denselben Typ festlegen, um zu verhindern, dass sich der Compiler beschwert.
Ich meine, ist es möglich, eine negative Polsterung zu haben? Wenn ja, dann behalten Sie es als int. Andernfalls sollten Sie wahrscheinlich unsigned int verwenden und den Stream die Situationen abfangen lassen, in denen der Benutzer eine negative Zahl eingibt.
quelle
oder verwenden Sie diese Header-Bibliothek und schreiben Sie:
// |notEqaul|less|lessEqual|greater|greaterEqual if(sweet::equal(valueA,valueB))
und kümmere dich nicht um signierte / nicht signierte oder andere Größen
quelle
Das Hauptproblem besteht darin, dass die zugrunde liegende Hardware, die CPU, nur Anweisungen zum Vergleichen von zwei vorzeichenbehafteten Werten oder von zwei vorzeichenlosen Werten enthält. Wenn Sie der vorzeichenlosen Vergleichsanweisung einen vorzeichenbehafteten, negativen Wert übergeben, wird dieser als große positive Zahl behandelt. Also wird -1, das Bitmuster mit allen eingeschalteten Bits (Zweierkomplement), der maximale vorzeichenlose Wert für die gleiche Anzahl von Bits.
8-Bit: -1 vorzeichenbehaftet sind die gleichen Bits wie 255 vorzeichenlose 16-Bit: -1 vorzeichenbehaftet sind die gleichen Bits wie 65535 vorzeichenlos usw.
Wenn Sie also den folgenden Code haben:
int fd; fd = open( .... ); int cnt; SomeType buf; cnt = read( fd, &buf, sizeof(buf) ); if( cnt < sizeof(buf) ) { perror("read error"); }
Sie werden feststellen, dass cnt auf -1 gesetzt wird, wenn der Aufruf von read (2) fehlschlägt, weil der Dateideskriptor ungültig wird (oder ein anderer Fehler vorliegt). Beim Vergleich mit sizeof (buf), einem vorzeichenlosen Wert, ist die if () - Anweisung falsch, da 0xffffffff nicht kleiner als sizeof () einer (vernünftigen, nicht als maximale Größe zusammengestellten) Datenstruktur ist.
Daher müssen Sie das obige if schreiben, um die signierte / nicht signierte Warnung wie folgt zu entfernen:
if( cnt < 0 || (size_t)cnt < sizeof(buf) ) { perror("read error"); }
Dies spricht nur laut zu den Problemen.
1. Introduction of size_t and other datatypes was crafted to mostly work, not engineered, with language changes, to be explicitly robust and fool proof. 2. Overall, C/C++ data types should just be signed, as Java correctly implemented.
Wenn Sie Werte haben, die so groß sind, dass Sie keinen signierten Werttyp finden, der funktioniert, verwenden Sie einen zu kleinen Prozessor oder eine zu große Anzahl von Werten in der Sprache Ihrer Wahl. Wenn wie beim Geld jede Ziffer zählt, gibt es Systeme, die in den meisten Sprachen verwendet werden können und die Ihnen eine unendliche Genauigkeit bieten. C / C ++ macht das einfach nicht gut, und Sie müssen sehr explizit über alles rund um Typen sein, wie in vielen anderen Antworten hier erwähnt.
quelle