Eine Warnung – Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen ganzzahligen Ausdrücken

Eine Warnung – Vergleich zwischen vorzeichenbehafteten und vorzeichenlosen ganzzahligen Ausdrücken

Es ist normalerweise eine gute Idee, Variablen als unsigned zu deklarieren oder size_t wenn sie mit Größen verglichen werden, um dieses Problem zu vermeiden. Verwenden Sie nach Möglichkeit genau den Typ, mit dem Sie vergleichen werden (verwenden Sie beispielsweise std::string::size_type beim Vergleich mit einem std::string 's Länge).

Compiler warnen vor dem Vergleich von vorzeichenbehafteten und vorzeichenlosen Typen, weil die Bereiche von vorzeichenbehafteten und vorzeichenlosen Ganzzahlen 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 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();
}

Ich hatte gestern genau das gleiche Problem, als ich Problem 2-3 in Accelerated C++ durchgearbeitet habe. Der Schlüssel besteht darin, alle Variablen, die Sie vergleichen (mit booleschen Operatoren), in kompatible Typen zu ändern. In diesem Fall bedeutet das string::size_type (oder unsigned int , aber da dieses Beispiel ersteres verwendet, 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 darauf hingewiesen haben.

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

Um zu Ihrem Beispiel zu kommen, würde der von Ihnen gepostete Code am Ende so aussehen:

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 initialisiert hätten im for Schleife. Sie müssen also die for-Schleife mit etwas wie:

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

Also im Grunde, sobald Sie einen string::size_type einführen Variable in den Mix einfügen, jedes Mal, wenn Sie eine boolesche Operation an diesem Element ausführen möchten, müssen alle Operanden einen kompatiblen Typ haben, damit es ohne Warnungen kompiliert werden kann.


Der wichtige Unterschied zwischen signiert und unsigniert besteht in der Interpretation des letzten Bits. Die letzten Bits in vorzeichenbehafteten Typen stellen das Vorzeichen der Zahl dar, d. h.:z. B.:

0001 ist 1 mit Vorzeichen und ohne Vorzeichen1001 ist -1 mit Vorzeichen und 9 ohne Vorzeichen

(Ich habe das ganze Komplementproblem aus Gründen der Klarheit der Erklärung vermieden! Dies ist nicht genau die Art und Weise, wie Ints im Speicher dargestellt werden!)

Sie können sich vorstellen, dass es einen Unterschied macht, ob Sie mit -1 oder mit +9 vergleichen. In vielen Fällen sind Programmierer einfach zu faul, das Zählen von Ganzzahlen als vorzeichenlos zu deklarieren (wodurch der for-Schleifenkopf aufgebläht wird, z. Deshalb ist es nur eine Warnung. Weil wir zu faul sind, 'unsigned' statt 'int' zu schreiben.