我正在查看一些 C++ 代码,我看到:
byte b = someByteValue;
// take twos complement
byte TwosComplement = -b;
此代码是否采用 b 的二进制补码?如果不是,它在做什么?
原文由 amalgamate 发布,翻译遵循 CC BY-SA 4.0 许可协议
我正在查看一些 C++ 代码,我看到:
byte b = someByteValue;
// take twos complement
byte TwosComplement = -b;
此代码是否采用 b 的二进制补码?如果不是,它在做什么?
原文由 amalgamate 发布,翻译遵循 CC BY-SA 4.0 许可协议
在二进制补码机器上,否定计算二进制补码,是的。
在 Unisys 上,一些东西,希望现在已经死去并被埋葬(但几年前仍然存在),没有签名类型。
C 和 C++ 支持有符号整数的二进制补码、一个补码和符号和大小表示,并且只有使用二进制补码才能进行二进制补码。
使用 byte
作为无符号类型否定加上转换为 byte
产生二进制补码位模式,无论整数表示如何,因为转换为无符号和无符号算术是模 2 _n_其中 n 是值表示位数。
也就是说,用-x赋值或初始化后的结果是2 n - x,它是x的二进制补码。
这并不意味着否定本身必然计算二进制补码位模式。 To understand this, note that with byte
defined as unsigned char
, and with sizeof(int)
> 1, the byte
value is promoted to int
在否定之前,即否定操作是用有符号类型完成的。但是将得到的负值转换为无符号字节,根据定义创建二进制补码位模式以及模算术和转换为无符号类型的 C++ 保证。
2 的补码形式的用处如下 2 n - x = 1 + ((2 n - 1) - x),其中最后一个括号是全一的位模式减去 x ,即 x
的简单按位反转 ---
.
原文由 Cheers and hth. - Alf 发布,翻译遵循 CC BY-SA 3.0 许可协议
3 回答2k 阅读✓ 已解决
2 回答3.9k 阅读✓ 已解决
2 回答3.2k 阅读✓ 已解决
1 回答3.2k 阅读✓ 已解决
1 回答2.7k 阅读✓ 已解决
3 回答3.5k 阅读
1 回答3.3k 阅读
在
stdint.h
定义uint8_t
的任何实现中, 此 代码肯定会计算 8 位二进制数的二进制补码:那是因为, 如果
uint8_t
可用,它必须是正好 8 位宽的无符号类型。转换为unsigned int
是必要的,因为uint8_t
肯定比int
窄。如果没有转换,该值将在被否定之前提升为int
,因此,如果您在非二进制补码机器上,它将不会采用二进制补码。更一般地说,此代码计算具有 任何 无符号类型的值的二进制补码(使用 C++ 构造进行说明 - 一元减号的行为在两种语言中是相同的,假设没有用户定义的重载):
因为一元减号被定义为在应用于无符号类型时采用二进制补码。我们仍然需要转换为不小于
int
的无符号类型,但现在我们需要它至少尽可能宽T
,因此uintmax_t
.但是,一元减法 不一定 计算类型为 signed 的值的二进制补码,因为 C(和 C++)仍然明确允许基于 不 使用二进制补码的 CPU 实现有符号量。据我所知,至少有 20 年没有生产过这样的 CPU,所以继续为它们提供供应有点愚蠢,但确实如此。如果你想计算一个值的二进制补码,即使它的类型恰好是有符号的,你必须这样做:(再次使用 C++)
即转换为相应的无符号类型,然后转换为
uintmax_t
, 然后 应用一元减号,然后反向转换为可能有符号的类型。 (需要强制转换为 U 以确保该值为零而不是从其自然宽度进行符号扩展。)(但是,如果您发现自己这样做了,请停止并将相关类型更改为无符号。您未来的自己会感谢您。)