C语言之按位取反~(七十一)
计算机存储数据基本知识
计算机中二进制数包括(正数和负数)是以补码形式存储。
符号位:补码的最左侧首位是符号位,0表示正数,1表示负数。
二进制有三种形式:原码、反码、补码。
正数的补码和反码:是正数本身(原码)。
负数的反码:符号位不变(是1),其余位按位取反,不用加一。
负数的补码:符号位不变(是1),先按位取反,再加一。(即是反码加一)
在计算机内存中,负数以补码形式存在(即取反,再加一)。
计算机并不直接存储二进制原码,而是存储二进制的补码。正数的补码就是原码。比如1,原码0000 0001,补码也为0000 0001。就存储的是原码0000 00001.
而计算机不直接存储负数,而是存储负数的补码,负数的补码计算规则是"符号位不变,原码取反再加一"。
例如:-1怎么存储的?
原码1000 0001
取反1111 1110,
加一1111 1111
1111 1111就是-1的二进制补码。
当负数要输出给别的程序用的时候怎么办呢?总不能把存储的补码给别人的吧?给人用之前需要将补码逆向再转换成原码,否则数据就不对了。
负数转换补码的规则:取反,再加一,符号不变。
那么:
补码转换原码的规则:符号不变,先减一,再取反。
这样就得到原码,可以输出了。
将正数和负数按位取反(~)
特别注意:
"~"符号取反的用法,场景也不一样,同样是"~"符号,有的是求反码,有的是求补码,所以要搞清楚。
举两个例子说明:
<1>.代码示例一
#include <stdio.h>
int main(){
int a = 0;
printf("~0 = %d\n",~a);
a = 1;
printf("~1 = %d\n",~a);
a = 2;
printf("~2 = %d\n",~a);
a = -1;
printf("~(-1) = %d\n",~a);
a = -2;
printf("~(-2) = %d\n",~a);
}
打印:
~0 = -1
~1 = -2
~2 = -3
~(-1) = 0
~(-2) = 1
~0步骤
步骤1:首先计算出0的补码,即它本身
步骤2:因为0的补码是负数,所以要还原其原码在输出;
0的补码和反码是他本身,再对0按位取反,就变成1111 1111,因为最高位为1,所以为负数,负数是以补码的形式存储,所以输出时要转换成正确的原码。
因为原码转补码的规则是:先取反,再加一
所以补码转原码的规则是:先减一,再取反。
步骤1:首先计算出0的补码,即它本身
0的原码的补码是他本身:
0000 0000
步骤2:因为0的补码是负数,所以要还原其原码在输出
~0:即所有位数,按位取反
1111 1111
当你要输出的时候,编译器发现最高位符号位是1,这个数是个负数,而负数在计算机里面是用补码存储的,所以此时计算机认为这个1111 1111是补码,它要转换成原码输出,于是先减去1,除了符号位不变,其他位全部取反。
因为原码转补码的规则是:先取反,再加一
所以补码转原码的规则是:先减一,再取反。
减一操作:
1111 1110
取反操作
1000 0001 = -1
~1步骤
步骤1:首先计算出1的补码,即它本身
步骤2:因为1的补码是负数,所以要还原其原码在输出;
因为原码转补码的规则是:先取反,再加一
所以补码转原码的规则是:先减一,再取反。
步骤1:首先计算出1的补码,即它本身
1的原码的补码是他本身:
0000 0001
步骤2:因为1的补码是负数,所以要还原其原码在输出;
~1的反码:即所有位数,按位取反
1111 1110
如果要输出打印,此时编译器发现其为最高位为1,是个负数,负数在计算机里面是用补码存储的,所以此时计算机认为这个1111 1110是补码,它要转换成原码输出,于是先减去1,除了符号位不变,其他位全部取反。
减一操作:
1111 1101
取反操作
1000 0010 = -2
~(-1)步骤
步骤1:首先计算出-1的补码(因为负数在计算机中以补码形式存在)
步骤2:再对-1的补码按位取反
步骤1:首先计算出-1的补码
-1的原码:
1000 0001
-1的反码:即按位取反(负号不变)
1111 1110
加一
1111 1111
步骤2:再对-1的补码按位取反,包括符号位
~(1111 1111) =0000 0000 = 0
~(-2)步骤
步骤1:首先计算出-2的补码因为负数在计算机中以补码形式存在)
步骤2:再对-2的补码按位取反
步骤1:首先计算出-2的补码因为负数在计算机中以补码形式存在)
-2的原码:
1000 0010
-2的反码:即按位取反(负号不变)
1111 1101
加一
1111 1110
步骤2:再对-2的补码按位取反
0000 0001 = 1
<2>.代码示例二:按位取反参与多项运算
#include <stdio.h>
int flag = 0x104; //0000 0001 0000 0100
int flag2 = 0x04;
printf("flag2 = %#x\n",flag2);
printf("~flag2 = %#x\n",~flag2);
int b = flag & ~flag2;
printf("b = %#x\n",b);
return 0;
}
打印:
flag2 = 0x4
~flag2 = 0xfffffffb
b = 0x100
求flag & ~flag2
1.flag = 0x104
二进制原码:
0000 0001 0000 0100
2.flag2 = 0x04
二进制原码:
0000 0000 0000 0100
~flag2(按位取反):
1111 1111 1111 1011
flag与上flag2的反码
0000 0001 0000 0100
1111 1111 1111 1011
= 0000 0001 0000 0000 = 0x100
所以b = 0x100,和计算机打印的一样。
相关文章
- c语言中按位异或的作用,C语言 按位异或实现加法(示例代码)
- 初学C语言的福音-初识关键字和指针
- [linux] C语言Linux系统编程-捕获进程信号详解编程语言
- [编程] C语言循环结构计算π的值详解编程语言
- C语言中文网QQ交流群汇总
- Linux C语言开发——让系统更加强大(linux c 开发)
- 界面 Linux C语言实现图形化界面开发指南(linuxc语言图形)
- 深入了解C语言中的MySQL语法(c 中mysql语法)
- 使用C语言与MySQL实现登陆功能(c mysql 登陆)
- 掌握利器从入门到精通的C语言与MySQL(c mysql怎么使用)
- 利用C语言编写Oracle建表脚本快速方便(c oracle建表脚本)
- php读取二进制流(C语言结构体struct数据文件)的深入解析
- C语言对堆排序一个算法思路和实现代码