如何在c++中取字节的二进制补码?

mzmfm0qo  于 2022-12-15  发布在  其他
关注(0)|答案(4)|浏览(214)

我正在查看一些C++代码,我看到:

byte b = someByteValue;
 // take twos complement
 byte TwosComplement = -b;

这段代码是取B的二进制补码吗?如果不是,它在做什么?

zpgglvta

zpgglvta1#

  • 此 * 代码在stdint.h定义uint8_t的任何实现中,都可以计算8位二进制数的二进制补码:
#include <stdint.h>
uint8_t twos_complement(uint8_t val)
{
    return -(unsigned int)val;
}

这是因为,* 如果 * uint8_t是可用的,它必须是一个无符号类型,正好是8位宽。转换到unsigned int是必要的,因为uint8_t肯定比int窄。如果没有转换,值将在求反之前提升到int,所以,如果你在一个非二进制补码的机器上,它将不取二进制补码。
更一般地说,这段代码计算一个 any unsigned类型的值的二进制补码(使用C++结构来说明--一元减号的行为在两种语言中是相同的,假设没有用户定义的重载):

#include <cstdint>
#include <type_traits>

template <typename T>
T twos_complement(T val,
                  // "allow this template to be instantiated only for unsigned types"
                  typename std::enable_if<std::is_unsigned<T>::value>::type* = 0)
{
    return -std::uintmax_t(val);
}

因为一元减号被定义为在应用于无符号类型时取二进制补码。我们仍然需要强制转换为不窄于int的无符号类型,但现在我们需要它至少与任何可能的T一样宽,因此是uintmax_t
但是,一元减号 * 不 * 一定计算类型为 signed 的值的二进制补码,因为C(和C++)仍然明确允许基于CPU的实现,这些CPU * 不 * 对有符号量使用二进制补码。据我所知,至少20年来没有制造过这样的CPU,所以继续提供它们有点愚蠢,但事实就是这样,如果你想计算一个值的二进制补码,即使它的类型碰巧是有符号的,你必须这样做:(还是C++)

#include <type_traits>

template <typename T>
T twos_complement(T val)
{
    typedef std::make_unsigned<T>::type U;

    return T(-uintmax_t(U(val)));
}

例如,转换为相应的无符号类型,然后转换为uintmax_t,* 然后 * 应用一元减号,然后反向转换为可能有符号的类型。(需要强制转换为U,以确保值为零,而不是从其自然宽度进行符号扩展。)
(If不过,如果你发现自己在这样做,那就停下来,把有问题的类型改为无符号的。你未来的自己会感谢你的。)

hmtdttj4

hmtdttj42#

正确的表达式如下

byte TwosComplement = ~b + 1;

注:假定字节定义为unsigned char

7xzttuei

7xzttuei3#

在二进制补码上,机器求反运算计算二进制补码,是的。
在Unisys上,希望现在已经死了,埋了(但几年前仍然存在),没有签名的类型。
C和C支持二进制补码、一进制补码和有符号整数的符号和大小表示,并且只有在二进制补码的情况下,求反才能做二进制补码。
byte作为无符号类型,求反加上到byte的转换产生二进制补码位模式,而不管整数表示,因为到无符号以及无符号算术的转换是模2n,其中 n 是值表示位的数目。
也就是说,用-x赋值或初始化后得到的值是2n - x,它是x的二进制补码。
这并不意味着求反运算本身必须计算二进制补码位模式。要理解这一点,请注意,如果byte定义为unsigned char,并且sizeof(int)〉1,则在求反运算之前,byte值将提升为int,即求反运算是使用有符号类型完成的。但将结果负值转换为无符号字节时,通过定义以及C
对模运算和无符号类型转换的保证创建二进制补码位模式。
2的补码形式的有用性由2n - x = 1 +((2n - 1)- x)得出,其中最后一个括号是全1位模式减去 x,即x的简单逐位求逆。

gopyfrb3

gopyfrb34#

字节二进制数的twos_complement代码:

int byte[] = {1, 0, 1, 1, 1, 1, 1, 1};

if (byte[0] != 0){
    
    for (int i = 0; i < 8; i++){
        if (byte[i] == 1)
          byte[i] = 0;
        else
          byte[i] = 1;
      }
    
    for (int j = 7; j >= 0; j--){
        if (byte[j] == 0){
            byte[j] = 1;
            break;
          }
        else {
            byte[j] = 0;
          }
      }
    
  }

for (int i = 0; i < 8; i++)
  cout << byte[i];
cout << endl;

相关问题