2016-05-07 15 views
2

Das Programm wird gedruckt "Eingestellt die Schleife", wenn ich input.size() - 1 als For-Schleife-Bedingung verwenden.Weird std :: string :: size() in einer for-Schleife

std::string input; 
input = {""}; 
int i = 0; 
for (; i < input.size() - 1; ++i) 
{ 
    cout << "Entered the loop" << endl; 
} 

Wenn ich jedoch den Wert von input.size() -1 auf eine ganze Zahl (checksize) übergeben:

std::string input; 
input = {""}; 
int checksize = input.size() - 1; 
int i = 0; 
for (; i < checksize; ++i) 
{ 
    cout << "Entered the loop" << endl; 
} 

dann wird das Programm nicht in die Schleife gehen und wird nicht „die Schleife eingetreten“ print

Ich habe mich gefragt, warum das passiert? Es scheint, dass die zwei Teile des Codes für mich gleich sind.

+0

keine Compiler-Warnungen? – LogicStuff

+1

Die meisten Compiler haben standardmäßig eine signierte-unsignierte Warnung, die viele Fehlalarme generiert. Einige Compiler warnen vor einer Zuweisung außerhalb des Bereichs im 2. Beispiel –

+0

. Deshalb sollten Zahlen, die für Mathe verwendet werden, unterzeichnet werden. – Barry

Antwort

4

Sie sind ein Opfer von unsigned ganzen Zahlen :)

std::string::size() gibt eine unsigned integer (vom Typ entspricht size_t).

Wenn der Compiler wertet input.size() - 1, diese Art von wird size_t(0) - 1, und da die Berechnung mit unsigned ganzen Zahlen durchgeführt wird, statt -1 Sie eine sehr große ganze Zahl (MSVC 32-Bit-Compiler drucken 4294967295, erhalten, die entspricht bis zum maximal 32-Bit unsigned Integer-Wert 2^32 - 1).

Also diese Schleife:

for (int i = 0; i < input.size() - 1; ++i) 

ist eine Art entspricht:

for (int i = 0; i < /* very big positive number */; ++i) 

, die Ihre Nachricht viele mal gedruckt werden.

Stattdessen im zweiten Fall, wenn man input.size() - 1 auszuwerten und ordnen sie dann zu einem int Variable (die signed Standardeinstellung), der Compiler berechnet noch size_t(0) - 1 als eine sehr große positive ganze Zahl ist, aber dann ist diese Zahl umgewandelt zu einem (signed) int, mit -1 in checksize dazu führt, dass initialisiert und die Schleife wird nie ausgeführt:

for (int i = 0; i < checksize /* -1 */; ++i) 

in Anbetracht diesen übersetzbar Code:

#include <iostream> 
#include <string> 
using namespace std; 

int main() 
{ 
    string input; 

#ifdef CASE1 
    for (int i = 0; i < input.size() - 1; ++i) 
    { 
     cout << "Entered the loop\n"; 
    } 
#else 
    cout << "input.size() - 1 == " << (input.size() - 1) << '\n'; 
    cout << "SIZE_MAX   == " << SIZE_MAX << '\n'; 

    int checkSize = input.size() - 1; 
    cout << "checkSize == " << checkSize << '\n'; 

    for (int i = 0; i < checkSize; ++i) 
    { 
     cout << "Entered the loop\n"; 
    } 
#endif 
} 

Wenn Sie seine CASE1 mit MSVC und /W4 (Warnstufe 4, die ich sehr vorschlagen) kompilieren, erhalten Sie eine Warnung für Ihre for Schleifenbedingung:

cl /EHsc /W4 /nologo /DCASE1 test.cpp 

test.cpp(10) : warning C4018: '<' : signed/unsigned mismatch 

, die normalerweise auf Sie zeigt, dass etwas mit Ihrem Code nicht stimmt. Statt

, ohne CASE1 Kompilieren gibt keine Warnungen und die folgende Ausgabe (was zeigt, dass die körpereigene for Schleife nie ausgeführt):

cl /EHsc /W4 /nologo test.cpp 

input.size() - 1 == 4294967295 
SIZE_MAX   == 4294967295 
checkSize == -1 
+2

'input.size() - 1' ist eine vorzeichenlose Berechnung, auch wenn sie später int zugewiesen wurde. Der Compiler berechnet "0 - 1" nicht als solchen; es konvertiert 4294967295 in int. (was nicht garantiert ist, das gleiche Ergebnis zu geben, aber wahrscheinlich wird) –

2

input.size() ist eine vorzeichenlose Menge. Wenn es also Null ist, ergibt die Subtraktion von 1 den maximalen Wert für seinen Typ (eine große positive ganze Zahl, wahrscheinlich SIZE_MAX).

So wird die Schleife eingegeben, weil 0 < SIZE_MAX wahr ist. Wenn Sie diese große positive Zahl in int konvertieren, liegt die Nummer außerhalb des Bereichs für int. So Implementierung definiert Verhalten auftritt, die wahrscheinlich produziert checksize == -1. Dann wird Ihre Schleife nicht eingegeben, weil 0 < -1 falsch ist.