如何强制编译器或解释器看二进制数的二进制补码?

时间:2021-10-25 20:45:26

This is a simple C++ program:

这是一个简单的C ++程序:

#include <iostream>
#include <string>
using namespace std;

int main()
{
int x=0b10000001;
cout<<"Your number is :"<<x;
}

Output:

Your number is : 129

你的电话号码是:129

This is its Python counterpart also:

这也是它的Python对应物:

>>> i=0b10000001
>>> print i
129
>>> 

I want to know, how can I force the C compiler or Python interpreter to see my variable as a two's complement number and print -127 instead of 129?

我想知道,我怎样才能强制C编译器或Python解释器将我的变量视为二进制补码并打印-127而不是129?

I can write a function to do what I want (i.e. check the most significant bit and print the desired value), but I want to know, where numbers behaved as two's complement and when they behaved like a plain binary value in programming?

我可以写一个函数来做我想要的(即检查最重要的位并打印所需的值),但我想知道,数字表现为两个补码,当它们在编程中表现得像一个普通的二进制值?

The question is :

问题是 :

When binary variables behaved as a two's complement number and when they behaved as a plain binary number?

当二进制变量表现为二进制补码数并且它们表现为普通二进制数时?

5 个解决方案

#1


Simplest no-casting way I know how:

最简单的无铸造方式我知道如何:

i = i - 2*(i & (1 << 7))

where i is any integer type at least big enough for your target value, and where 7 should be replaced by the position of the sign bit (7 for 8-bit numbers, 15 for 16-bit numbers, etc.).

其中i是任何至少足够大的目标值的整数类型,其中7应该被符号位的位置替换(8位数字为7,16位数字为15,等等)。

This works because the sign bit in a signed integer is best interpreted as being the negative of its usual value. For example, the sign bit of an 8-bit number means -128, not +128. This little snippet of code basically subtracts twice the sign bit's value, to turn +128 into -128.

这是有效的,因为有符号整数中的符号位最好被解释为其通常值的负数。例如,8位数的符号位表示-128,而不是+128。这段代码基本上减去了符号位值的两倍,将+128变为-128。

Example from Python:

Python的例子:

>>> i = 129
>>> i = i - 2*(i & (1 << 7))
>>> i
-127

When programming, the type of a value determines how that value's bit pattern will be interpreted by the program. An unsigned value interprets the bit pattern without any sign bit (so that values cannot be negative) while a signed value interprets it with a sign bit (in twos-complement). In C, the sign bit is the most significant bit of a fixed-width integer. By forcibly casting a value to a smaller size, you can change which bit is considered the sign bit; this is why printing

编程时,值的类型决定了程序如何解释该值的位模式。无符号值解释位模式而没有任何符号位(因此值不能为负),而有符号值则用符号位(用二进制补码)解释它。在C中,符号位是固定宽度整数的最高有效位。通过强制将值转换为较小的值,可以更改哪个位被视为符号位;这就是打印的原因

(signed char)129

in C will give you -127.

在C中会给你-127。

Note that Python does not have a built-in unsigned type; all integers are signed but they can be arbitrarily big (unlike C, where integers are constrained to fit in a specific number of bits). Thus, my answer shows you how to get a signed value without using casting; it is applicable both to C and Python.

请注意,Python没有内置的无符号类型;所有整数都是有符号的,但它们可以是任意大的(与C不同,其中整数被约束为适合特定的位数)。因此,我的回答显示了如何在不使用强制转换的情况下获取有符号值;它适用于C和Python。

#2


The constant 0b10000001 has its eight bit set to one.

常量0b10000001将其8位设置为1。

When loaded into a 32- ou 64-bit int variable x , the leftmost bit is 0 so it is a positive value.

当加载到32-ou 64位int变量x时,最左边的位为0,因此它是一个正值。

#3


The binary representation of a negative number does not work the way you think. It is not a simple two's complement, if the sign-bit is set. So a sign-flip operation on a number is not just setting the sign-bit like x ^= (1 << 7). Instead, the binary representation of a binary number is x = ~x + 1. If x is then interpreted as a signed integer, it will print the negative value, if however you treat the integer as unsigned, you will get 255 - x + 1, whatever that may be.

负数的二进制表示不符合您的想法。如果设置了符号位,它不是简单的二进制补码。因此,对数字进行符号翻转操作不仅仅是将符号位设置为x ^ =(1 << 7)。相反,二进制数的二进制表示是x = ~x + 1.如果x被解释为有符号整数,它将打印负值,如果你将整数视为无符号,你将得到255 - x + 1,无论可能是什么。

For a bit width of 8bit, see this example:

对于8位的位宽,请参阅此示例:

#include <iostream>

int main()
{
   int8_t x = 0b10000001;
   int8_t y = 0b11111111;
   std::cout << "x as signed int is :" << int(x) << '\n';  // prints -127
   std::cout << "x as unsigned is :  " << int(uint8_t(x)) << '\n'; // 129
   std::cout << "y as signed int is :" << int(y) << '\n';          // -1
   std::cout << "y as unsigned is :  " << int(uint8_t(y)) << '\n'; // 255
   uint8_t z = 1;
   std::cout << "z ^ (1 << 7) = " << int(int8_t(z ^ (1 << 7))) << '\n'; // -127
   std::cout << "~z + 1       = " << int(int8_t(~z + 1)) << '\n';       // -1
}

When printing the value to stdout, you have to cast it back to int, otherwise it will be interpreted as a char which will most likely be non-printable characters.

将值打印到stdout时,必须将其强制转换为int,否则它将被解释为char,很可能是不可打印的字符。

As int8_t is an extension of C++11, you have to compile this program with --std=c++11.

由于int8_t是C ++ 11的扩展,因此必须使用--std = c ++ 11编译该程序。

#4


Here is an interesting way to do it in python:

这是在python中执行此操作的有趣方法:

>>> from struct import *
>>> i = 0b10000001
>>> print unpack('b', pack('B', i))[0]
-127
>>>

pack() returns a byte string representation of a number, based on a conversion code.

pack()根据转换代码返回数字的字节字符串表示形式。

pack('B', i) gives '\x81' IE the a single character byte string, the character is the one who's unsigned binary representation (specified by the 'B') is 10000001

pack('B',i)给'\ x81'IE一个字符字节字符串,该字符是无符号二进制表示(由'B'指定)的字符是10000001

unpack() takes a byte string and turns it into a list of numbers, based on a conversion code for each byte.

unpack()接受一个字节字符串,并根据每个字节的转换代码将其转换为数字列表。

unpack('b', '\x81') returns (-127), because that is what binary 10000001 means when interpreted as a signed binary char (which is what the 'b' specifies).

unpack('b','\ x81')返回(-127),因为这是二进制10000001在解释为带符号二进制字符时的含义(这是'b'指定的)。

[0] is used to select the first (and only) element of the list returned by unpack().

[0]用于选择unpack()返回的列表的第一个(也是唯一的)元素。

#5


An expression just using the value once:

只使用一次值的表达式:

>>> (0b10000001 + 128) % 256 - 128
-127

Or (after seeing nneonneo's answer):

或者(在看到nneonneo的回答之后):

>>> i - (i >> 7 << 8)
-127

#1


Simplest no-casting way I know how:

最简单的无铸造方式我知道如何:

i = i - 2*(i & (1 << 7))

where i is any integer type at least big enough for your target value, and where 7 should be replaced by the position of the sign bit (7 for 8-bit numbers, 15 for 16-bit numbers, etc.).

其中i是任何至少足够大的目标值的整数类型,其中7应该被符号位的位置替换(8位数字为7,16位数字为15,等等)。

This works because the sign bit in a signed integer is best interpreted as being the negative of its usual value. For example, the sign bit of an 8-bit number means -128, not +128. This little snippet of code basically subtracts twice the sign bit's value, to turn +128 into -128.

这是有效的,因为有符号整数中的符号位最好被解释为其通常值的负数。例如,8位数的符号位表示-128,而不是+128。这段代码基本上减去了符号位值的两倍,将+128变为-128。

Example from Python:

Python的例子:

>>> i = 129
>>> i = i - 2*(i & (1 << 7))
>>> i
-127

When programming, the type of a value determines how that value's bit pattern will be interpreted by the program. An unsigned value interprets the bit pattern without any sign bit (so that values cannot be negative) while a signed value interprets it with a sign bit (in twos-complement). In C, the sign bit is the most significant bit of a fixed-width integer. By forcibly casting a value to a smaller size, you can change which bit is considered the sign bit; this is why printing

编程时,值的类型决定了程序如何解释该值的位模式。无符号值解释位模式而没有任何符号位(因此值不能为负),而有符号值则用符号位(用二进制补码)解释它。在C中,符号位是固定宽度整数的最高有效位。通过强制将值转换为较小的值,可以更改哪个位被视为符号位;这就是打印的原因

(signed char)129

in C will give you -127.

在C中会给你-127。

Note that Python does not have a built-in unsigned type; all integers are signed but they can be arbitrarily big (unlike C, where integers are constrained to fit in a specific number of bits). Thus, my answer shows you how to get a signed value without using casting; it is applicable both to C and Python.

请注意,Python没有内置的无符号类型;所有整数都是有符号的,但它们可以是任意大的(与C不同,其中整数被约束为适合特定的位数)。因此,我的回答显示了如何在不使用强制转换的情况下获取有符号值;它适用于C和Python。

#2


The constant 0b10000001 has its eight bit set to one.

常量0b10000001将其8位设置为1。

When loaded into a 32- ou 64-bit int variable x , the leftmost bit is 0 so it is a positive value.

当加载到32-ou 64位int变量x时,最左边的位为0,因此它是一个正值。

#3


The binary representation of a negative number does not work the way you think. It is not a simple two's complement, if the sign-bit is set. So a sign-flip operation on a number is not just setting the sign-bit like x ^= (1 << 7). Instead, the binary representation of a binary number is x = ~x + 1. If x is then interpreted as a signed integer, it will print the negative value, if however you treat the integer as unsigned, you will get 255 - x + 1, whatever that may be.

负数的二进制表示不符合您的想法。如果设置了符号位,它不是简单的二进制补码。因此,对数字进行符号翻转操作不仅仅是将符号位设置为x ^ =(1 << 7)。相反,二进制数的二进制表示是x = ~x + 1.如果x被解释为有符号整数,它将打印负值,如果你将整数视为无符号,你将得到255 - x + 1,无论可能是什么。

For a bit width of 8bit, see this example:

对于8位的位宽,请参阅此示例:

#include <iostream>

int main()
{
   int8_t x = 0b10000001;
   int8_t y = 0b11111111;
   std::cout << "x as signed int is :" << int(x) << '\n';  // prints -127
   std::cout << "x as unsigned is :  " << int(uint8_t(x)) << '\n'; // 129
   std::cout << "y as signed int is :" << int(y) << '\n';          // -1
   std::cout << "y as unsigned is :  " << int(uint8_t(y)) << '\n'; // 255
   uint8_t z = 1;
   std::cout << "z ^ (1 << 7) = " << int(int8_t(z ^ (1 << 7))) << '\n'; // -127
   std::cout << "~z + 1       = " << int(int8_t(~z + 1)) << '\n';       // -1
}

When printing the value to stdout, you have to cast it back to int, otherwise it will be interpreted as a char which will most likely be non-printable characters.

将值打印到stdout时,必须将其强制转换为int,否则它将被解释为char,很可能是不可打印的字符。

As int8_t is an extension of C++11, you have to compile this program with --std=c++11.

由于int8_t是C ++ 11的扩展,因此必须使用--std = c ++ 11编译该程序。

#4


Here is an interesting way to do it in python:

这是在python中执行此操作的有趣方法:

>>> from struct import *
>>> i = 0b10000001
>>> print unpack('b', pack('B', i))[0]
-127
>>>

pack() returns a byte string representation of a number, based on a conversion code.

pack()根据转换代码返回数字的字节字符串表示形式。

pack('B', i) gives '\x81' IE the a single character byte string, the character is the one who's unsigned binary representation (specified by the 'B') is 10000001

pack('B',i)给'\ x81'IE一个字符字节字符串,该字符是无符号二进制表示(由'B'指定)的字符是10000001

unpack() takes a byte string and turns it into a list of numbers, based on a conversion code for each byte.

unpack()接受一个字节字符串,并根据每个字节的转换代码将其转换为数字列表。

unpack('b', '\x81') returns (-127), because that is what binary 10000001 means when interpreted as a signed binary char (which is what the 'b' specifies).

unpack('b','\ x81')返回(-127),因为这是二进制10000001在解释为带符号二进制字符时的含义(这是'b'指定的)。

[0] is used to select the first (and only) element of the list returned by unpack().

[0]用于选择unpack()返回的列表的第一个(也是唯一的)元素。

#5


An expression just using the value once:

只使用一次值的表达式:

>>> (0b10000001 + 128) % 256 - 128
-127

Or (after seeing nneonneo's answer):

或者(在看到nneonneo的回答之后):

>>> i - (i >> 7 << 8)
-127