项目七 任务一 进制及位运算

项目七 进制及位运算
项目介绍
在进入本项目之前,现在我们想这样一个问题,编程是什么,编程其实就是编写代码,那么我们为什么要学习编程呢?因为我们想通知计算机来为我们服务,那计算机认识什么呢?答案是进制,为了更好的了解进制在此项目我们将来学习计算机进制的相关知识,本项目我将会学到C语言中的进制以及表示方式,接下来我们还会学到进制之间的转换,最后将会讲到位与运算。
项目目标
掌握进制的定义
掌握C语言进制的方式
掌握二进制,八进制,十六进制的转换
掌握位与运算
任务一 进制及位运算
任务描述
本任务时来学习C语言的进制,进制是一种计数的方式,常用的有二进制、八进制、十进制、十六进制。通过本任务对进制的学习熟悉进制的形式以及进制之间的转换。
学习目标
掌握二进制表示方式。
掌握八进制的表示方式。
掌握十六进制进制表示方式。
掌握进制之间的转换。
掌握按位与运算
相关知识
7-1-1 进制的概念
进制是一种计数的机制,它可以使用有效的数字符号代表所有的数值,对于任何一种进制。
进制是一种计数的方式,它可以使用有效的数字符号代表所有的数值,常用的有二进制、八进制、十进制、十六进制。任何数据在计算机内存中都是以二进制的形式存放的。
二进制数是以2为计算单元,满2进1位的数;八进制数是以8为计算单元,满8进1位的数。m进制就是满m进一,对于任何一个数字,我们都可以用不同的进制来表示,比如下表7-1所示,十进制数12,用二进制表示为1100,用八进制表示为14,用十六进制表示为0xC。
表7-1 十进制、二进制、八进制、十六进制之间数值

1.C语言的进制
在C语言中对于整数,有四种表示方式:
二进制:0,1 ,满2进1,以0b或是0B开头表示,注意C语言中没有二进制常数的表示方法。
例如:  int num1=0b10010;     //二进制
十进制:0-9 ,满10进1。
例如    int num2 = 210; //十进制
八进制:0-7 ,满8进1,以0开头表示。
例 int num3 = 01010;    //八进制
十六进制:0-9及A-F,满16进1. 以0x或0X开头表示。此处的A-F不区分大小写 。[A->10, B->11, C->12, D->13, E->14, F->15]
 例如:int num4 = 0x1010;//十六进制
2.各进制字C语言中的输出
C语言中常用的整数有 short、int 和 long 三种类型,通过 printf 函数,可以将它们以八进制、十进制和十六进制的形式输出。
前面的知识我们已经知道十进制的形式输出,这节我们重点讲解如何以八进制和十六进制的形式输出,下表列出了不同类型的整数、以不同进制的形式输出时对应的格式控制符如下表 7-2所示:

说明 :十六进制数字的表示用到了英文字母,有大小写之分,要在格式控制符中体现出来:
(1)%hx、%x 和 %lx 中的x小写,表明以小写字母的形式输出十六进制数;
(2)%hX、%X 和 %lX 中的X大写,表明以大写字母的形式输出十六进制数。
接下来我们一起演示一个案例:
实例7- 1实现各进制的输出。

#include <stdio.h>
int main()
{
    short a = 0b1010110;  //二进制数字
    int b = 02713;  //八进制数字
    long c = 0X1DAB83;  //十六进制数
/*以八进制形似输出*/
    printf("以八进制的形式输出 :a=%ho, b=%o, c=%lo\n", a, b, c);     
 /*以十进制形式输出*/
printf("以十进制的形式输出   :a=%hd, b=%d, c=%ld\n", a, b, c);
  /*以十六进制形式输出(字母小写)*/   
printf("十六进制的形式输出(小写):a=%hx, b=%x, c=%lx\n", a, b, c);
    /*以十六进制形式输出(字母大写)*/
    printf("十六进制的形式输出(大写):a=%hX, b=%X, c=%lX\n", a, b, c);     getchar();
    return 0;
}


运行结果:如图 7-1所示。

图7- 1 实例7-1进制的输出
上述案例中注意观察上面的例子,会发现有一点不完美,如果只看输出结果:对于八进制数字,它没法和十进制、十六进制区分,因为八进制、十进制和十六进制都包含 0~7 这几个数字。
区分不同进制数字的一个简单办法就是,在输出时带上特定的前缀。在格式控制符中加上#即可输出前缀,例如 %#x、%#o、%#lX、%#ho 等,请看下面的代码:
实例7- 2 实现带前缀的各进制的输出。

#include <stdio.h>
int main()
{
    short a = 0b1010110;  //二进制数字
    int b = 02713;  //八进制数字
    long c = 0X1DAB83;  //十六进制数字
/*以八进制形似输出*/
    printf("a=%#ho, b=%#o, c=%#lo\n", a, b, c);
/*以十进制形式输出*/
    printf("a=%hd, b=%d, c=%ld\n", a, b, c);
/*以十六进制形式输出(字母小写)*/
    printf("a=%#hx, b=%#x, c=%#lx\n", a, b, c);     
    /*以十六进制形式输出(字母大写)*/
 printf("a=%#hX, b=%#X, c=%#lX\n", a, b, c);
     return 0;
}


运行结果:如图7-2所示。

图7- 2 实例7-2进制的格式化输出
十进制数字没有前缀,所以不用加#。如果你加上了,那么它的行为是未定义的,有的编译器支持十进制加#,只不过输出结果和没有加#一样,有的编译器不支持加#,可能会报错,也可能会导致奇怪的输出;但是,大部分编译器都能正常输出,不至于当成一种错误。
7-1-2 进制之间的转换
一个数值不管是用哪一种进制表示,数值本身不会发生变化的,因此各进制之间可以实现转换,下面就以前面提高的十进制、二进制、八进制、十六进制为例来讲进制之间的转换。
1.十进制与二进制之间的相互转换
(1)实现二进制转换成十进制
规则:从最低位开始,将每个位上的数提取出来,乘以2的(位数-1)次方,然后求和。
案例:请将 二进制 1011 转成十进制的数
二进制 1011 = 1 * 2^0 + 1 * 2^1 + 0 * 2^2 + 1 * 2^3 = 1+2+0+8=11
(2)实现十进制转换成二进制
规则:将该数不断除以2,直到商为0为止,然后将每步得到的余数倒过来,就是对
应的二进制。
案例:请将 56 转成二进制 。
56 => 111000,转换过程如下图7-3所示。

图7- 3 十进制转换成二进制

2.十进制与八进制之间的相互转换
(1)实现八进制转换成十进制
规则:从最低位开始,将每个位上的数提取出来,乘以8的(位数-1)次方,然后求和。
案例:请将 0123 转成十进制的数
0123 = 3 * 8 ^ 0 + 2 * 8 ^ 1 + 1 * 8^2 = 3+16+64=83
(2)实现十进制转换成八进制
规则:将该数不断除以8,直到商为0为止,然后将每步得到的余数倒过来,就是对
应的八进制。
案例:请将 156 转成八进制
156 => 234,转换过程如下图7-4所示。

图7- 4 十进制转换成八进制
3.十进制与十六进制之间的相互转换
(1)实现十六进制转换成十进制
规则:从最低位开始,将每个位上的数提取出来,乘以16的(位数-1)次方,然后求和。
案例:请将 0x123 转成十进制的数
0123 = 3 * 16 ^ 0 + 2 * 16 ^ 1 + 1 * 16^2 = 291
(2)实现十进制转换成十六进制
规则:将该数不断除以16,直到商为0为止,然后将每步得到的余数倒过来,就是对
应的十六进制。
进制。
案例:请将 156 转成十六进制
156 => 9c,转换过程如下图7-5所示。


图7- 5 十进制转换成十六进制
7-1-3 按位与运算
位运算符是针对二进制数的每一位进行运算的符号。它是专门针对数字0和1进行操作的。C语言中的位运算符及其用法如表7-3所示。
表7-3位运算符及其用法

说明:为了区分十进制和其他进制,凡是非十进制的数据均在数据后面加上括号,括号中注明其进制,二进制则标记为2)内存储存数据的基本单位是字节(Byte),一个字节由8个位(bit)所组成。位是用以描述电脑数据量的最小单位。二进制系统中,每个0或1就是一个位。
接下来通过一些具体示例,对表中描述的位运算符进行详细介绍.
1.“按位与”运算符(&)
按位与是指:参加运算的两个数据,按二进制位进行“与”运算。如果两个相应的二进制位都为1,则该位的结果值为1;否则为0。这里的1可以理解为逻辑中的true,0可以理解为逻辑中的false。按位与其实与逻辑上“与”的运算规则一致。逻辑上的“与”,要求运算数全真,结果才为真。若,A=true,B=true,则A∩B=true
例如:
6&11,6对应的二进制数为00000110,11对应的二进制是00001011演算过程如下。
按位与运算:
00000110(2)
&
00001011(2)
-------------------------------------------------------
00000010(2)--->2
由此可知6&11=2
c语言代码:
    int a=6;
    int b=11;
    printf("%d",a&b);
2.按位或运算
两个相应的二进制位中只要有一个为1,该位的结果值为1。借用逻辑学中或运算的话来说就是,一真为真。
例如:6和11进行位或运算
00000110(2)
|
00001011(2)
-------------------------------------------------------
      00001111(2)--->15
由此可知6|11=15
c语言代码:
    int a=6;
    int b=11;
    printf("%d",a|b);

3 ”按位取反”运算
“取反”运算符(~),他是一元运算符,用于求整数的二进制反码,即分别将操作数各二进制位上的1变为0,0变为1。
例如:将6进行取反运算
按位与运算:
~  00000110(2)
-------------------------------------------------------
    11111001(2)--->-7
由此可知~6=-7
c语言代码:
    int a=6;
    printf("%d",~a);
4、”按位异或 ”运算
“异或”运算符(^)
他的规则是:若参加运算的两个二进制位值相同则为0,否则为1
即0^0=0,0^1=1,1^0=1, 1^1=0。
例如:6和11进行按位异或运算
00000110(2)
^
00001011(2)
-------------------------------------------------------
00001101(2)--->13
由此可知6^11=13
c语言代码:
    int a=6;
    int b=11;
    printf("%d",a^b);
5、什么是”按位左移”或者”右移”运算
左移运算符是用来将一个数的各二进制位左移若干位,移动的位数由右操作数指定(右操作数必须是非负值),其右边空出的位用0填补,高位左移溢出则舍弃该高位。
例如:将a的二进制数左移2位,右边空出的位补0,左边溢出的位舍弃。
若a=15,即00001111(2),左移2位得00111100(2)。
演算的过程
00001111<<2
-----------------------------------------
00111100(2)--->60
c语言的代码
int a=15;
printf("%d",a<<2);
右移运算符(>>)
右移运算符是用来将一个数的各二进制位右移若干位,移动的位数由右操作数指定(右操作数必须是非负值),移到右端的低位被舍弃,对于无符号数,高位补0。对于有符号数,某些机器将对左边空出的部分用符号位填补(即“算术移位”),而另一些机器则对左边空出的部分用0填补(即“逻辑移位”)。
例如:若a=11,即00001011(2),右移2位得00000010(2)。
演算的过程
00001111>>2
-----------------------------------------
00000010(2)--->2
c语言的代码
int a=11;
printf("%d",a>>2);



多学一招 
二进制的三码

问题来源:

"为毛   -x=!x+1  ???

其中x为一任意int型正整数,左式表示取x的相反数后的二进制形式,右式表示先将x的二进制按位取反后再加一得到的二进制形式。

左右两个二进制相同"

假设有一个 int 类型的数,值为5,那么,我们知道它在计算机中表示为:
00000000 00000000 00000000 00000101
5转换成二制是101,不过int类型的数占用4字节(32位),所以前面填了一堆0。
现在想知道,-5在计算机中如何表示?

在计算机中,负数以原码的补码形式表达。

什么叫补码呢?这得从原码,反码说起。

原码:一个正数,按照绝对值大小转换成的二进制数;一个负数按照绝对值大小转换成的二进制数,然后最高位补1,称为原码。
比如 00000000 00000000 00000000 00000101 是 5的 原码。
          10000000 00000000 00000000 00000101 是 -5的 原码。

反码:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
取反操作指:原为1,得0;原为0,得1。(1变0; 0变1)
比如:正数00000000 00000000 00000000 00000101 的反码还是 00000000 00000000 00000000 00000101
负数10000000 00000000 00000000 00000101每一位取反(除符号位),得11111111 11111111 11111111 11111010。
称:11111111 11111111 11111111 11111010 是 10000000 00000000 00000000 00000101 的反码。
反码是相互的,所以也可称:
10000000 00000000 00000000 00000101 和 11111111 11111111 11111111 11111010互为反码。

补码:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.
比如:10000000 00000000 00000000 00000101 的反码是:11111111 11111111 11111111 11111010。
那么,补码为:
11111111 11111111 11111111 11111010 + 1 = 11111111 11111111 11111111 11111011
所以,-5 在计算机中表达为:11111111 11111111 11111111 11111011。转换为十六进制:0xFFFFFFFB。
再举一例,我们来看整数-1在计算机中如何表示。
假设这也是一个int类型,那么:
1、先取-1的原码:10000000 00000000 00000000 00000001
2、得反码:     11111111 11111111 11111111 11111110(除符号位按位取反)
3、得补码:     11111111 11111111 11111111 11111111
可见,-1在计算机里用二进制表达就是全1。16进制为:0xFFFFFF


主要知识点:
正数的反码和补码都与原码相同。
而负数的反码为对该数的原码除符号位外各位取反。
负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1
下面是书上原文:
原码表示法规定:用符号位和数值表示带符号数,正数的符号位用“0”表示,负数的符号位用“1”表示,数值部分用二进制形式表示。
反码表示法规定:正数的反码与原码相同,负数的反码为对该数的原码除符号位外各位取反。
补码表示法规定:正数的补码与原码相同,负数的补码为对该数的原码除符号位外各位取反,然后在最后一位加1.
正零和负零的补码相同,[+0]补=[-0]补=0000 0000B

猜你喜欢

转载自blog.csdn.net/qq_27248989/article/details/106109445