在写代码的时候遇到一个位运算的bug,我将0的二进制00000000所有位都置为1后变成11111111,然后因为业务逻辑问题想对11111111做一个判断,判断语句为将一个字节的数字与11111111做比较,但是在匹配的时候我简单的将BYTE_NUM== 255
进行匹配,发现了程序出现bug,最后进行gdb调试的时候发现是这个匹配出的问题,最后细想了解到255只是11111111的源码,而C语言都是按照补码进行存储而11111111的补码是-1,最后我也没有与-1进行匹配而是加了个位运算~(0 << 7)
对于有符号整数255的补码为什么是-1,首先我们将数字存与字节中,所以一个数字大小应该一个字节,但是一个字节可以表示的有符号数字是-128到127之间(因为第一位要做符号位),那么255怎么表示呢?我们简单的将255存入一个字节的空间中变成11111111,其中11111111是-1的补码
换句话说将一个数字存入一个char类型的字节中(正常一个数字是存入4个字节中)是存入的该数字补码到字节中,但是如果数字大于127小于255也就是大于一个字节可存入的最大正数就按照其源码存储,
#include
#include
using namespace std;
int main()
{
char a;
a = 255;
printf("255 store in char,and pirnt each bit of this char\n");
for(int i = 0; i < 8; i++){
printf("%d",!!((a << i) & 0x80));
}
printf("\n");
a = -100;
printf("-100 store in char,and pirnt each bit of this char\n");
for(int i = 0; i < 8; i++){
printf("%d",!!((a << i) & 0x80));
}
printf("\n");
a = 100;
printf("100 store in char,and pirnt each bit of this char\n");
for(int i = 0; i < 8; i++){
printf("%d",!!((a << i) & 0x80));
}
printf("\n");
return 0;
}
输出如下,看到-100和100在一个字节内都是按照补码存储(100的源码是01100100,正数的源码和补码都一样),255是按照源码存储(因为没有地方存储符号位)
255 store in char,and pirnt each bit of this char
11111111
-100 store in char,and pirnt each bit of this char
10011100
100 store in char,and pirnt each bit of this char
01100100
我们再看存储257是啥样,因为257的二进制源码是0100000001
,第一个bit(0)是符号位代表正数,如果存入一个字节(char)中百分之百会发生截取,但是我们不知道是截取前8bit(从左往右截取)还是截取后8bit(从右往左截取)
#include
#include
using namespace std;
int main()
{
char a;
a = 257;
printf("257 store in char,and pirnt each bit of this char\n");
for(int i = 0; i < 8; i++){
printf("%d",!!((a << i) & 0x80));
}
printf("\n");
return 0;
}
输入如下,报了一个warning,告诉你将257存入一个字节中会发生overflow,但还是运行,最后发现编译器是从后往前截取
main.cpp: In function ‘int main()’:
main.cpp:9:9: warning: overflow in conversion from ‘int’ to ‘char’ changes value from ‘257’ to ‘'\001'’ [-Woverflow]
9 | a = 257;
| ^~~
257 store in char,and pirnt each bit of this char
00000001
总结
将一个数字存入一个char类型的字节中(正常一个数字是存入4个字节中)是存入的该数字补码到字节中,但是如果数字大于127小于255也就是大于一个字节可存入的最大正数就按照其补码存储,如果数字大于255那么会发生截取,比如将257存入一个字节的char中,先取257的补码(同源码)0100000001
然后从后向前截取8bit,最后为0000001