在 C++20 中从有符号整数到无符号整数,反之亦然

Going from signed integers to unsigned integers and vice versa in C++20

在 C++20 之前,不能保证有符号整数是二进制补码。现在我们有两篇论文提出将二进制补码标准化作为唯一表示:p0907 and p1236,如果我理解正确的话,其中一篇已合并到 C++20 工作草案中。

那么,有符号到无符号的转换是什么意思,反之亦然?我查看了 cppreference 并发现了以下措辞:

If the destination type is unsigned, the resulting value is the smallest unsigned value equal to the source value modulo 2<sup>n</sup> where n is the number of bits used to represent the destination type.

If the destination type is signed, the value does not change if the source integer can be represented in the destination type. Otherwise the result is the unique value of the destination type equal to the source value modulo 2<sup>n</sup> where n is the number of bits used to represent the destination type. (Note that this is different from signed integer arithmetic overflow, which is undefined).

不幸的是,我无法理解这个措辞,我想知道 C++20 Working Draft 中写的是什么。

所以有两个问题:

  1. 语言律师部分:有人可以指出标准的确切内容以及它在标准中的什么位置吗?

  2. 谁能用更通俗的术语解释一下这个措辞,可能还解释模运算并提供示例?

转换规则为[conv.integral]/3:

Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2<sup>N</sup>, where N is the range exponent of the destination type.

其中范围指数在 [basic.fundamental] 中的 table 中描述,但表示您所期望的(对于 int,它至少为 16,对于 long long,它在至少 64 等)。

例如,将值为-3short转换为unsigned short就是找到类型unsigned short-3全等的唯一值模 2<sup>16</sup>... 也就是说,2<sup>16</sup>-3 65533。但是将 -3 的相同 short 值转换为 unsigned long long 会将模基数更改为 2<sup>64</sup> ,所以你最终得到的是 18446744073709551613

从有符号类型转换为具有不同范围指数的有符号类型(或者同样地,无符号到无符号)更直接——您要么砍掉位,要么将它们零扩展。例如,将值为 258 的 short 转换为 intlonglong long 只是 258,但转换为 signed char 是 2。

你的引述用了很多词来表达一些非常简单的事情:对于每个整数 i,在 0M 之间恰好有一个整数 k 所以i % M == k(在数学意义上,不是“固定大小的整数表示”意义上)。通俗地说,i % M == k的意思是“如果我从i中加上或减去M正确的次数,我可以得到k”。

在整数转换的情况下,M = 2^N 其中 N 是目标类型中的位数。标准说:

[conv.integral]#3

Otherwise, the result is the unique value of the destination type that is congruent to the source integer modulo 2^N, where N is the range exponent of the destination type.

示例中:

假设您的目标类型有 4 位,因此它可以表示从 0152^4 = 16 个值。将 1 转换为该范围会产生 114 会产生 1415 会产生 1516 会产生 0, 17 产生 1, 18 产生 2 等等。转换 0 产生 0-1 产生 15-2 产生 14

如果您真的想要更深入地介绍模运算,那超出了本网站的范围。你应该参考网络上丰富的资源,比如this one.