如何使用c ++中的一个字节的二进制补码 [英] how to take twos complement of a byte in c++

查看:264
本文介绍了如何使用c ++中的一个字节的二进制补码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在看一些c ++代码,我看到:

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

这段代码是否使用b的二进制补码?如果不是,它在做什么?

解决方案

这个代码绝对会计算8位二进制数的二进制补码 stdint.h 定义 uint8_t



<$ p的任何实现$ p> #include< stdint.h>
uint8_t twos_complement(uint8_t val)
{
return - (unsigned int)val;
}

这是因为如果 uint8_t 可用,它必须是一个完全8位宽的无符号类型。必须转换为 unsigned int ,因为 uint8_t 明显比 int 。没有转换,该值将被提升为 int 之前,它被否定,所以,如果你在一个非二进制补充机器,它不会采取两 - 补充。



更一般地说,此代码使用任何无符号类型计算值的二进制补码(使用C ++结构进行说明 - 一元减去的行为在两种语言中是相同的,假设没有用户定义的重载):

  #include< cstdint> 
#include< type_traits>

template< typename T>
T twos_complement(T val,
//允许此模板仅针对无符号类型实例化
typename std :: enable_if< std :: is_unsigned< T> :: value> ;: :type * = 0)
{
return -std :: uintmax_t(val);
}

因为一元减数定义为在应用于无符号类型时采用二进制补码。我们仍然需要一个不小于 int 的无符号类型的转型,但现在我们需要它至少与任何可能的 T一样宽 $



但是,一元减号不是

em>必须计算类型为有符号的值的二进制补码,因为C(和C ++)仍然明确允许基于不使用twos的CPU实现补充有符号数量。据我所知,没有这样的CPU已经在至少20年制造,所以继续规定他们是一种愚蠢,但它是。如果你想计算一个值的二进制补码,即使它的类型恰好被签名,你必须这样做:(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,以确保该值为零,而不是从其自然宽度的符号扩展。)



(如果你发现自己这样做, ,停止并将相关类型更改为unsigned,您的未来自我将感谢您。)


I am looking at some c++ code and I see:

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

Is this code taking the twos complement of b? If not, What is it doing?

解决方案

This code definitely does compute the twos-complement of an 8-bit binary number, on any implementation where stdint.h defines uint8_t:

#include <stdint.h>
uint8_t twos_complement(uint8_t val)
{
    return -(unsigned int)val;
}

That is because, if uint8_t is available, it must be an unsigned type that is exactly 8 bits wide. The conversion to unsigned int is necessary because uint8_t is definitely narrower than int. Without the conversion, the value will be promoted to int before it is negated, so, if you're on a non-twos-complement machine, it will not take the twos-complement.

More generally, this code computes the twos-complement of a value with any unsigned type (using C++ constructs for illustration - the behavior of unary minus is the same in both languages, assuming no user-defined overloads):

#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);
}

because unary minus is defined to take the twos-complement when applied to unsigned types. We still need a cast to an unsigned type that is no narrower than int, but now we need it to be at least as wide as any possible T, hence uintmax_t.

However, unary minus does not necessarily compute the twos-complement of a value whose type is signed, because C (and C++) still explicitly allow implementations based on CPUs that don't use twos-complement for signed quantities. As far as I know, no such CPU has been manufactured in at least 20 years, so the continued provision for them is kind of silly, but there it is. If you want to compute the twos-complement of a value even if its type happens to be signed, you have to do this: (C++ again)

#include <type_traits>

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

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

i.e. convert to the corresponding unsigned type, then to uintmax_t, then apply unary minus, then back-convert to the possibly-signed type. (The cast to U is required to make sure the value is zero- rather than sign-extended from its natural width.)

(If you find yourself doing this, though, stop and change the types in question to unsigned instead. Your future self will thank you.)

这篇关于如何使用c ++中的一个字节的二进制补码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆