为什么 (18446744073709551615 == -1) 是真的?
Why is (18446744073709551615 == -1) true?
当我在 string::npos
上工作时,我注意到了一些事情,但我在网上找不到任何解释。
(string::npos == ULONG_MAX)
和
(string::npos == -1)
是真的。
所以我尝试了这个:
(18446744073709551615 == -1)
这也是事实。
这怎么可能?是因为二元对话吗?
string::npos
被定义为 constexpr static std::string::size_type string::npos = -1;
(或者如果它是在 class 定义中定义的,那将是 constexpr static size_type npos = -1;
,但这真的无关紧要)。
转换为无符号类型的负数的环绕(std::string::size_type
基本上是 std::size_t
,它是无符号的)在标准中有完美的定义。 -1
换行到无符号类型的最大可表示值,在您的情况下为 18446744073709551615
。请注意,确切的值是实现定义的,因为 std::size_t
的大小是实现定义的(但能够保存所讨论系统上最大可能数组的大小)。
根据C++标准(文档号:N3337或文档号:N4296)std::string::npos
定义如下
static const size_type npos = -1;
其中 std::string::size_type 是一些无符号整数类型。所以 std::string::npos 等于 -1 并没有什么了不起的。初始化器被转换为 std::string::npos
.
的类型
至于这个等式
(string::npos == ULONG_MAX) is true,
则表示类型std::string::npos
在使用的实现中有类型unsigned long
。该类型通常对应类型size_t
.
在这个等式中
(18446744073709551615 == -1)
左边的文字有一些无符号整数类型,适合存储这么大的文字。因此,通过传播符号位,右操作数也被转换为这种无符号类型。由于左操作数本身代表该类型的最大值,因此它们相等。
这都是关于有符号溢出和负数存储为 2 补码的事实。这意味着要获得负数的绝对值,您需要反转所有位并加一。进行 8 位比较时的含义 255 和 -1 具有相同的二进制值 11111111。这同样适用于更大的整数
18,446,744,073,709,551,615
提到的这个数字 18,446,744,073,709,551,615
实际上是 2^64 − 1
。这里重要的是 2^64-1
本质上是基于 0 的 2^64
。无符号整数的第一位是 0
,而不是 1
。所以如果最大值是1
,它有两个可能的值:0
,或者1
(2).
让我们看看2^64 - 1
在64位二进制中,所有位都打开。
1111111111111111111111111111111111111111111111111111111111111111b
-1
让我们看看 64 位二进制文件中的 +1
。
0000000000000000000000000000000000000000000000000000000000000001b
为了使 One's Complement (OCP) 中的负值,我们将位反转。
1111111111111111111111111111111111111111111111111111111111111110b
计算机很少使用OCP,他们使用Two's Complement (TCP)。要获得 TCP,请向 OCP 添加一个。
1111111111111111111111111111111111111111111111111111111111111110b (-1 in OCP)
+ 1b (1)
-----------------------------------------------------------------
1111111111111111111111111111111111111111111111111111111111111111b (-1 in TCP)
"But, wait"你问,如果在二进制补码中-1
是,
1111111111111111111111111111111111111111111111111111111111111111b
并且,如果在二进制中 2^64 - 1
是
1111111111111111111111111111111111111111111111111111111111111111b
那么他们是平等的!而且,这就是你所看到的。您正在将带符号的 64 位整数与无符号的 64 位整数进行比较。在 C++ 中,这意味着将有符号值转换为无符号值,编译器会这样做。
更新
对于技术更正 ,从 signed
的 -1
到相同大小的 unsigned
类型的转换实际上在语言中指定,并且不是架构的功能。总而言之,您可能会发现上面的答案对于理解 arch/languages 是有用的,它支持双语的赞美但缺乏确保您可以依赖的结果的规范。
当我在 string::npos
上工作时,我注意到了一些事情,但我在网上找不到任何解释。
(string::npos == ULONG_MAX)
和
(string::npos == -1)
是真的。
所以我尝试了这个:
(18446744073709551615 == -1)
这也是事实。
这怎么可能?是因为二元对话吗?
string::npos
被定义为 constexpr static std::string::size_type string::npos = -1;
(或者如果它是在 class 定义中定义的,那将是 constexpr static size_type npos = -1;
,但这真的无关紧要)。
转换为无符号类型的负数的环绕(std::string::size_type
基本上是 std::size_t
,它是无符号的)在标准中有完美的定义。 -1
换行到无符号类型的最大可表示值,在您的情况下为 18446744073709551615
。请注意,确切的值是实现定义的,因为 std::size_t
的大小是实现定义的(但能够保存所讨论系统上最大可能数组的大小)。
根据C++标准(文档号:N3337或文档号:N4296)std::string::npos
定义如下
static const size_type npos = -1;
其中 std::string::size_type 是一些无符号整数类型。所以 std::string::npos 等于 -1 并没有什么了不起的。初始化器被转换为 std::string::npos
.
至于这个等式
(string::npos == ULONG_MAX) is true,
则表示类型std::string::npos
在使用的实现中有类型unsigned long
。该类型通常对应类型size_t
.
在这个等式中
(18446744073709551615 == -1)
左边的文字有一些无符号整数类型,适合存储这么大的文字。因此,通过传播符号位,右操作数也被转换为这种无符号类型。由于左操作数本身代表该类型的最大值,因此它们相等。
这都是关于有符号溢出和负数存储为 2 补码的事实。这意味着要获得负数的绝对值,您需要反转所有位并加一。进行 8 位比较时的含义 255 和 -1 具有相同的二进制值 11111111。这同样适用于更大的整数
18,446,744,073,709,551,615
提到的这个数字 18,446,744,073,709,551,615
实际上是 2^64 − 1
。这里重要的是 2^64-1
本质上是基于 0 的 2^64
。无符号整数的第一位是 0
,而不是 1
。所以如果最大值是1
,它有两个可能的值:0
,或者1
(2).
让我们看看2^64 - 1
在64位二进制中,所有位都打开。
1111111111111111111111111111111111111111111111111111111111111111b
-1
让我们看看 64 位二进制文件中的 +1
。
0000000000000000000000000000000000000000000000000000000000000001b
为了使 One's Complement (OCP) 中的负值,我们将位反转。
1111111111111111111111111111111111111111111111111111111111111110b
计算机很少使用OCP,他们使用Two's Complement (TCP)。要获得 TCP,请向 OCP 添加一个。
1111111111111111111111111111111111111111111111111111111111111110b (-1 in OCP)
+ 1b (1)
-----------------------------------------------------------------
1111111111111111111111111111111111111111111111111111111111111111b (-1 in TCP)
"But, wait"你问,如果在二进制补码中-1
是,
1111111111111111111111111111111111111111111111111111111111111111b
并且,如果在二进制中 2^64 - 1
是
1111111111111111111111111111111111111111111111111111111111111111b
那么他们是平等的!而且,这就是你所看到的。您正在将带符号的 64 位整数与无符号的 64 位整数进行比较。在 C++ 中,这意味着将有符号值转换为无符号值,编译器会这样做。
更新
对于技术更正 signed
的 -1
到相同大小的 unsigned
类型的转换实际上在语言中指定,并且不是架构的功能。总而言之,您可能会发现上面的答案对于理解 arch/languages 是有用的,它支持双语的赞美但缺乏确保您可以依赖的结果的规范。