I'm confused why the following code produces this output:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int i = -1;
string s = "abc";
int j = s.size();
int x = 1 % 3;
int y = i % j;
int z = i % s.size();
cout << s.size() << endl; // 3
cout << x << endl; // 1
cout << y << endl; // -1
cout << z << endl; // 0
}
Why is z = 0? Does it have to do with casting?
So, stripping down your code to a minimal example, you're asking why this prints 0
:
#include <iostream>
#include <string>
int main()
{
int a = -1;
std::string::size_type b = 3;
int c = a % b;
std::cout << c << '\n';
}
The primary operation in question here is this:
a % b
Per the standard,
5.6 Multiplicative operators [expr.mul]
- The operands of * and / shall have arithmetic or unscoped enumeration type; the operands of % shall have integral or unscoped enumeration type. The usual arithmetic conversions are performed on the operands and determine the type of the result.
So.. what about those "usual arithmetic conversions"? This is to mate the types of the two operands to a common type prior to performing the actual operation. The following are considered in order :
That's a lot of legalize for what effectively says this:
signed int
and a std::string::size_type
std::string::size_type
is greater than that of signed int
signed int
operand is converted to type std::string:size_type
prior to the operation being requested.So all that is left is the conversion, to wit, there is one more piece of legalize:
4.7 Integral conversions [conv.integral]
- If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type). [Note: In a two’s complement representation, this conversion is conceptual and there is no change in the bit pattern (if there is no truncation). —end note]
That means, on a 32-bit std::string::size_type
platform, you're going to get 232-1 as the converted value from int
(-1).
Which means...
4294967295 % 3
Which is... zero. If std::string::size_type
is 64-bits, then everything above stays the same, save for the final calculation, which would be:
18446744073709551615 % 3