C++ 如何在c ++中取一个字节的二进制补码

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25754082/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 11:25:19  来源:igfitidea点击:

how to take twos complement of a byte in c++

c++bytetwos-complement

提问by amalgamate

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

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

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

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

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

回答by zwol

Thiscode definitely does compute the twos-complement of an 8-bit binary number, on any implementation where stdint.hdefines uint8_t:

这段代码确实计算了一个 8 位二进制数的二进制补码,在任何stdint.h定义的实现中uint8_t

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

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

这是因为,如果uint8_t可用,它必须是恰好 8 位宽的无符号类型。转换 tounsigned int是必要的,因为uint8_t肯定比int. 如果没有转换,该值将在int取反之前被提升,因此,如果您使用的是非二进制补码机器,则不会采用二进制补码。

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

更一般地,此代码计算具有任何无符号类型的值的二进制补码(使用 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);
}

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.

因为当应用于无符号类型时,一元减号被定义为采用二进制补码。我们仍然需要转换为不小于 的无符号类型int,但现在我们需要它至少尽可能宽T,因此uintmax_t.

However, unary minus does notnecessarily compute the twos-complement of a value whose type is signed, because C (and C++) still explicitly allow implementations based on CPUs that don'tuse 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)

然而,一元减号也没有必要计算其类型的值的二进制补码,因为C(和C ++)仍明确允许基于这样的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)));
}

i.e. convert to the corresponding unsigned type, then to uintmax_t, thenapply 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.)

即转换为相应的无符号类型,然后转换为uintmax_t然后应用一元减号,然后反向转换为可能有符号的类型。(需要强制转换为 U 以确保该值为零而不是从其自然宽度进行符号扩展。)

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

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

回答by Vlad from Moscow

The correct expression will look

正确的表达会看起来

byte TwosComplement = ~b + 1;

Note: provided that byte iis defined as unsigned char

注意:假设字节 ii 定义为 unsigned char

回答by Cheers and hth. - Alf

On a two's complement machine negation computes the two's complement, yes.

在二进制补码机器上,否定计算二进制补码,是的。

On the Unisys something-something, hopefully now dead and buried (but was still extant a few years ago), no for a signed type.

在 Unisys 上的某物,希望现在已经死了并被埋葬了(但几年前仍然存在),没有签名类型。

C and C++ supports two's complement, one's complement and sign-and-magnitude representation of signed integers, and only with two's complement does negation do a two's complement.

C 和 C++ 支持二进制补码、一的补码和有符号整数的符号和大小表示,并且只有用二的补码进行取反才能做二的补码。



With byteas an unsigned type negation plus conversion to byteproduces the two's complement bitpattern, regardless of integer representation, because conversion to unsigned as well as unsigned arithmetic is modulo 2nwhere nis the number of value representation bits.

byte为一个无符号类型否定加转换到byte产生二的补码位模式,而不管整数表示的,因为转化成无符号以及无符号算术是模2 Ñ其中Ñ是值表示比特的数量。

That is, the resulting value after assigning or initializing with -x is 2n- x which is the two's complement of x.

也就是说,使用 -x 赋值或初始化后的结果值为 2 n- x,它是 x 的二进制补码。

This does not mean that the negation itself necessarily computes the two's complement bitpattern. To understand this, note that with bytedefined as unsigned char, and with sizeof(int)> 1, the bytevalue is promoted to intbefore the negation, i.e. the negation operation is done with a signed type. But converting the resulting negative value to unsigned byte, creates the two's complement bitpattern by definition and the C++ guarantee of modulo arithmetic and conversion to unsigned type.

这并不意味着否定本身必须计算二进制补码位模式。要理解这一点,请注意,byte定义为unsigned char,并且sizeof(int)> 1 时,该byteint在否定之前被提升,即否定操作是使用有符号类型完成的。但是将生成的负值转换为无符号字节,根据定义和 C++ 保证模算术和转换为无符号类型创建二进制补码位模式。



The usefulness of 2's complement form follows from 2n- x = 1 + ((2n- 1) - x), where the last parenthesis is an all-ones bitpattern minus x, i.e. a simple bitwise inversion of x.

2 的补码形式的用处来自 2 n- x = 1 + ((2 n- 1) - x),其中最后一个括号是一个全 1 位模式减去x,即 的简单按位反转x