[英]Why does the C++ modulo operator return 0 for -1 % str.size()?
I'm confused why the following code produces this output:我很困惑为什么下面的代码会产生这个 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?为什么z = 0? Does it have to do with casting?
跟选角有关系吗?
What really happens here:这里真正发生了什么:
int z = i % s.size();
is i
is converted to size_t
because the other side s.size()
is size_t
. is
i
被转换为size_t
因为另一边s.size()
是size_t
。 And unlike int
, size_t
is unsigned;与
int
不同, size_t
是无符号的; That is to say the value is interpreted as a positive number.也就是说,该值被解释为正数。
Check the output of this line:检查这一行的output:
std::cout << (size_t)-1 << std::endl;
to see what -1 has become.看看 -1 变成了什么。
So, stripping down your code to a minimal example, you're asking why this prints 0
:因此,将您的代码简化为一个最小的示例,您会问为什么会打印
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] 5.6 乘法运算符 [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
signed int
和一个std::string::size_type
std::string::size_type
is greater than that of signed int
std::string::size_type
的秩大于signed int
signed int
operand is converted to type std::string:size_type
prior to the operation being requested.signed int
操作数在请求操作之前被转换为std::string:size_type
类型。 So all that is left is the conversion, to wit, there is one more piece of legalize:所以剩下的就是转换,也就是说,还有一个合法化:
4.7 Integral conversions [conv.integral] 4.7 积分转换[conv.integral]
- If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2 n where n is the number of bits used to represent the unsigned type).
如果目标类型是无符号的,则结果值是与源 integer 一致的最小无符号 integer(模 2 n ,其中 n 是用于表示无符号类型的位数)。 [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 2 32 -1 as the converted value from int
(-1).这意味着,在 32 位
std::string::size_type
平台上,您将获得 2 32 -1 作为来自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:如果
std::string::size_type
是 64 位,那么上面的一切都保持不变,除了最后的计算,这将是:
18446744073709551615 % 3
@GhaziMajdoub's answer is correct, but - why don't you let the compiler tell you what's happening? @GhaziMajdoub 的回答是正确的,但是 - 你为什么不让编译器告诉你发生了什么?
Let's use the Flags to enable thorough and verbose g++ warnings ...让我们使用标志来启用彻底和详细的 g++ 警告......
$ g++ -pedantic -Wall -Wextra -Wcast-align -Wcast-qual -Wctor-dtor-privacy \
-Wdisabled-optimization -Wformat=2 -Winit-self -Wlogical-op -Wmissing-declarations \
-Wmissing-include-dirs -Wnoexcept -Wold-style-cast -Woverloaded-virtual \
-Wredundant-decls -Wshadow -Wsign-conversion -Wsign-promo -Wstrict-null-sentinel \
-Wstrict-overflow=5 -Wswitch-default -Wundef -Werror -Wno-unused -o a a.cpp
a.cpp: In function ‘int main()’:
a.cpp:12:13: error: conversion to ‘std::__cxx11::basic_string<char>::size_type’ {aka
‘long unsigned int’} from ‘int’ may change the sign of the result
[-Werror=sign-conversion]
12 | int z = i % s.size();
| ^
cc1plus: all warnings being treated as errors
a.cpp: In function ‘int main()’:
a.cpp:12:13: warning: conversion to ‘std::__cxx11::basic_string<char>::size_type’
{aka ‘long unsigned int’} from ‘int’ may change the sign of the result [-Wsign-
conversion]
12 | int z = i % s.size();
| ^
and there you have it: i
is converted to long unsigned int
, so it's no longer -1
.你有它:
i
被转换为long unsigned int
,所以它不再是-1
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.