The program will print "Entered the loop" if I use input.size() - 1
as the for loop condition.
std::string input;
input = {""};
int i = 0;
for (; i < input.size() - 1; ++i)
{
cout << "Entered the loop" << endl;
}
However, if I pass the value of input.size() -1
to an integer (checksize
):
std::string input;
input = {""};
int checksize = input.size() - 1;
int i = 0;
for (; i < checksize; ++i)
{
cout << "Entered the loop" << endl;
}
then the program will not go into the loop and will not print "Entered the loop"
I was wondering why this happen? It seems the two pieces of code are the same to me.
You are a victim of unsigned integers :)
std::string::size()
returns an unsigned integer (of type equivalent to size_t
).
When the compiler evaluates input.size() - 1
, this kind of becomes size_t(0) - 1
, and since the computation is done with unsigned integers, instead of -1 you get a very big integer number (MSVC 32-bit compiler prints 4294967295
, which corresponds to the maximum 32-bit unsigned integer value 2^32 - 1
).
So this loop:
for (int i = 0; i < input.size() - 1; ++i)
is kind of equivalent to:
for (int i = 0; i < /* very big positive number */; ++i)
which will print your message many times.
Instead, in the second case, when you evaluate input.size() - 1
and then assign it to an int
variable (which is signed
by default), the compiler still computes size_t(0) - 1
as a very big positive integer number, but then this number is converted to a (signed
) int
, resulting in checksize
being initialized with -1
, and your loop is never executed:
for (int i = 0; i < checksize /* -1 */; ++i)
Considering this compilable 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
}
If you compile its CASE1
with MSVC and /W4
(warning level 4, which I highly suggest), you get a warning for your for
loop condition:
cl /EHsc /W4 /nologo /DCASE1 test.cpp test.cpp(10) : warning C4018: '<' : signed/unsigned mismatch
which usually points to you that something is wrong with your code.
Instead, compiling without CASE1
, gives no warnings and the following output (which shows that the for
loop's body is never executed):
cl /EHsc /W4 /nologo test.cpp input.size() - 1 == 4294967295 SIZE_MAX == 4294967295 checkSize == -1