Here is why one should be very careful while mixing signed and unsigned integer comparisons. Take a look at this code snippet below:
#include <iostream> #include <string> int main(int argc, char *argv[]) { std::string presidentsOrders = "NO lets do more sanctions"; unsigned int pos; pos = presidentsOrders.find("YES"); if (pos != std::string::npos) { std::cout << "Lets nuke North Korea" << std::endl; } else { std::cout << "More sanctions (yawn)" << std::endl; } return 0; }
The President does not want to nuke North Korea, but lets see how the program actually interprets this. If you try compiling and executing this program in a 32-bit environment, it will work as it should:
abhi@devserver:~/cpp_string_pos$ ./a.out More sanctions (yawn) abhi@devserver:~/cpp_string_pos$
Now compile the same program in a 64-bit environment (you can cross-compile using the -m32 or -m64 flag in g++). Here is the result:
abhi@devserver:~/cpp_string_pos$ g++ cpp_string_pos32.cpp -m64 abhi@devserver:~/cpp_string_pos$ ./a.out Lets nuke North Korea abhi@devserver:~/cpp_string_pos$
So we effectively misinterpreted the order to fire the nuclear missile. The problem is that std::string::npos is a size_t type and usually defined as:
static const size_t npos = -1;
This is 0xFFFFFFFF
on 32-bit, but becomes 0xFFFFFFFFFFFFFFFF
on 64-bit. The comparison on 64-bit is then between the unsigned int pos which is upconverted to 0x00000000FFFFFFFF
and 0xFFFFFFFFFFFFFFFF
causing the check to fail and the nuke getting fired. So the right thing to do here is to use std::string::size_type for pos
instead which would store the right value in the pos
variable. This is of course an exaggerated example, and I do hope that missile systems have more levels of strict checks that need to be cleared before they get fired, but it showcases how disastrous this kind of mistake can be. Poor choices of data types for variables can really run your program into the ground.