iOS开发-C语言-进制的转换

来源:互联网 发布:手机短信软件 编辑:程序博客网 时间:2024/05/22 09:49

一、进制
1.什么是进制
• 是一种计数的方式,数值的表示形式
2.二进制
• 特点:只有0和1,逢2进1
• 书写格式:0b或者0b开头
o 二进制 以0b 或者 0B开头
o 八进制 以0开头
o 十六进制 以0x或者0X开头
• 使用场合:二进制指令\二进制文件,变量在内存中就是二进制存储
• n为二进制位所能表示的数据范围(不考虑负数):0~2的n次方-1
3.八进制
• 特点:0~7,逢八进一
• 书写格式:0开头
4.十六进制
• 特点:0~F,逢十六进一
• 书写格式:0x或者0X开头
5.总结
1>mac中计算器的使用
2>printf以不同形式进行输出

进制的应用

#include <stdio.h>int main(int argc, const char * argv[]) {    int a = 13;    printf("%d\n",a);    printf("%o\n",a);    printf("%x\n",a);    int b = 0b00000000000000000000000000001101;    printf("%d\n",b);    int b1 = 015;    printf("%d\n",b1);    int b3 = 0x520A;    printf("%d\n",b3);    return 0;}

二、常见的进制转换
转换:有得时候转换为人能识别的数制,要操作计算机写计算机能够识别的语言(二进制)
10 -> 2 : 除2取余法,把10进制数除以2,然后取得余数的序列,再倒序
2 -> 10 : 所有位的位权相加 101 = 1*2^0+0*2^1+1*2^2
2 –> 16 : 4合1法, 整数部分从右向左 4位结合成一位,小数部分从左向右4位结合1位, 不足部分补0
16 –>2 : 1拆4法, 16进制的1位拆成二进制的4位
2–>8:3合1
8–>2:1拆3
10–>8 :除8取余
8 –> 10 : 8–> 2 –> 10
16 –> 10: 16 –>2 –>10

进制转换应用

#include <stdio.h>void changeTo2(int n){    int len = sizeof(n) * 8;    int temp;    for (int i=0; i<len; i++) {        temp = n;          temp = temp>>31-i;               int t = temp & 1;        printf("%d",t);    }    printf("\n");}int main(int argc, const char * argv[]) {    changeTo2(13);    return 0;}

三、机器数和真值的概念
1、机器数和真值
1)机器数
一个数在计算机中的二进制表示形式, 叫做这个数的机器数。机器数是带符号的,在计算机 用一个数的最高位存放符号, 正数为0, 负数为1.
比如,十进制中的数 +3 ,计算机字长为8位,转换成二进制就是00000011。如果是 -3 ,就 是 10000011 。 那么,这里的 00000011 和 10000011 就是机器数。
2)真值
因为第一位是符号位,所以机器数的形式值就不等于真正的数值。
例如上面的有符号数 10000011,其最高位1代表负,其真正数值是 -3 而不是形式值131(10000011转换成十进制等于 131)。
所以,为区别起见,将带符号位的机器数对应的真正数值称为机器数的真值。
例:0000 0001的真值 = +000 0001 = +1,
1000 0001的真值 = –000 0001 = –1

四、原码反码补码概念及转换
1、原码、反码、补码的基本概念.
在探求为何机器要使用补码之前, 让我们先了解原码, 反码和补码的概念.对于一个数, 计算机要 使用一定的编码方式进行存储. 原码, 反码, 补码是机器存储一个具体数字的编码方式.
原码, 反码, 补码是计算机原理的术语。说白了就是为了理解计算机2进制用的。对于C/C++来 说,是和数据类型有关的。

数据在计算机中的存储方法:
数据在计算机内部是以补码的形式储存的
数据分为有符号数和无符号数, 无符号数都为正数,由十进制直接转换到二进制直接存储(其实也是该十进制的补码)即可。 有符号数用在计算机内部是以补码的形式储存的。( 正数的最高位是符号位0,负数的最高位是 符号位1。
对于正数:反码==补码==原码。
对于负数:反码==除符号位以外的各位取反。补码=反 码+1)
正数的首位地址为0,其源码是由十进制数转换到的二进制数字 负数的首位地址为1,其源码后面的位也为10进制数转换过去的二进制数字,都是用补码方式表示 有符号数的。

1)原码
原码就是符号位加上真值的绝对值, 即用第一位表示符号, 其余位表示值. 比如如果是8位二进制:
第一位是符号位. 因为第一位是符号位, 所以8位二进制数的取值范围就是:

原码是人脑最容易理解和计算的表示方式.

2)反码
反码的表示方法是:
正数的反码是其本身
负数的反码是在其原码的基础上, 符号位不变,其余各个位取反.

可见如果一个反码表示的是负数, 人脑无法直观的看出来它的数值. 通常要将其转换成原码再计 算.
3)补码
补码的表示方法是:
正数的补码就是其本身
负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
对于负数, 补码表示方式也是人脑无法直观看出其数值的. 通常也需要转换成原码在计算其数值.
2、 -1在内存中存储细节
在64位计算机中,-1的原码、反码、补码如下
-1原码 1000 0000 0000 0000 0000 0000 0000 0001
-1反码 1111 1111 1111 1111 1111 1111 1111 1110
-1补码 1111 1111 1111 1111 1111 1111 1111 1111

补码的转换

#include <stdio.h>int main(int argc, const char * argv[]) {    int b = 0b11111111111111111111111111110011;    printf("b = %d\n",b);    return 0;}

源码补码转换

#include <stdio.h>int main(int argc, const char * argv[]) {    int b1 =0b000000000000000000000000000000001;    printf("b1 = %d\n",b1);    int b2 = 0b111111111111111111111111111111111;    printf("b2 = %d\n",b2);    return 0;}

五、为什么要引入反码、补码?

  1. 为什么要引入反码和补码?
    在开始深入学习前, 我的学习建议是先”死记硬背”上面的原码, 反码和补码的表示方式以及计算 方法.
    现在我们知道了计算机可以有三种编码方式表示一个数. 对于正数因为三种编码方式的结果都相 同:
    所以不需要过多解释. 但是对于负数:
    可见原码, 反码和补码是完全不同的. 既然原码才是被人脑直接识别并用于计算表示方式, 为何还会有反码和补码呢?
    首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位, 选择对真值区域的 加减. (真值的概念在本文最开头). 但是对于计算机, 加减乘数已经是最基础的运算, 要设计的 尽量简单. 计算机辨别”符号位”显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了 将符号位也参与运算的方法. 我们知道, 根据运算法则减去一个正数等于加上一个负数, 即: 1-1 = 1 + (-1) = 0 , 所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了.
    2、补码的再深入(不要求掌握)
    计算十进制的表达式: 1-1=0
    1 -1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
    如果用原码表示, 让符号位也参与计算, 显然对于减法来说, 结果是不正确的.这也就是为何计算 机内部不使用原码表示一个数.
    为了解决原码做减法的问题, 出现了反码:
    计算十进制的表达式: 1-1=0
    = [0000 0001]反 + [1111 1110]反
    = [1111 1111]反
    = [1000 0000]原 (1111 1111,符号位不变,其他为逐位取反)
    = -0
    -1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原
    发现用反码计算减法, 结果的真值部分是正确的. 而唯一的问题其实就出现在”0”这个特殊的数值 上. 虽然人们理解上+0和-0是一样的, 但是0带符号是没有任何意义的. 而且会有[0000 0000]原和 [1000 0000]原两个编码表示0.
    于是补码的出现, 解决了0的符号以及两个编码的问题:
    = [0000 0001]补 + [1111 1111]补
    = [0000 0000]补
    = [0000 0000]原
    1-1 = 1 + (-1) = [0000 0001]原 + [1000 0001]原
    这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了.而且可以用[1000 0000]表示-128:
    (-1) + (-127) = [1000 0001]原 + [1111 1111]原 = [1111 1111]补 + [1000 0001]补 = [1000 0000]补
    -1-127的结果应该是-128, 在用补码运算的结果中, [1000 0000]补 就是-128. 但是注意因为实际 上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码

实际 上是使用以前的-0的补码来表示-128, 所以-128并没有原码和反码表示.(对-128的补码表示[1000 0000]补算出来的原码是[0000 0000]原, 这是不正确的)
单字节的表示的最大的负数是多少?
[10000000]补
=[10000000]反+1
=11111111+1
=(1)00000000 =00000000(最高位溢出了,符号位变成了0)
有人会问 10000000这个补码表示的哪个数的补码呢? 其实这是一个规定,这个数表示的是-128 所以n位补码能表示的范围是 -2^(n-1)到2^(n-1)-1 比n位原码能表示的数多一个

六、位运算符介绍
1、位运算符介绍
位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。 C语言提供了6个位操作运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的 char,short,int与long类型。
1)& 按位与
只有对应的两个二进位均为1时,结果位才为1,否则为0 口诀: 同1为1
例如:
9&13 = 9

2) | 按位或
只要对应的二个二进位有一个为1时,结果位就为1,否则为0
1001
& 1101
——————— 1101
3) ^ 按位异或
当对应的二进位相异(不相同)时,结果为1,否则为0
1001
^ 1101
———————- 0100
4) ~ 取反
各二进位进行取反(0变1,1变0)
~9 =-10
9的原码:0000 0000 0000 0000 0000 0000 0000 1001
反码:1111 1111 1111 1111 1111 1111 1111 0110 //-10
知道补码求原码:也是符号位不变,其他各位取反+1
1111 1111 1111 1111 1111 0110
取反
1000 0000 0000 0000 0000 1001+11000 0000 0000 0000 0000 1010 //-10

1、<< 左移
1、各二进位全部左移n位,高位丢弃,低位补0
1)左移可能会改变一个数的正负性
2)左移1位想当于*2
x << n 左移 x 的所有二进制位向左移动n位,移出位删掉,移进的位补零 左移注意:
2、用途:快速计算一个数乘以2的n次方(8<<3 等同于8*2^3)
2<<2 == 2*2
左移改变一个数的正负性:
2、>> 右移
各二进位全部右移n位,保持符号位不变
x >> n x的所有二进制位向右移动n位,移出的位删掉,移进的位补符号位
x 右移 n 位就相当于除以2的n次方
1、右移不会改变一个数的符号
2、用途:快速计算一个数除以2的n次方(8>>3 等同于8/2^3)
左移改变一个数的正负性

2、>> 右移
各二进位全部右移n位,保持符号位不变
x >> n x的所有二进制位向右移动n位,移出的位删掉,移进的位补符号位
x 右移 n 位就相当于除以2的n次方
1、右移不会改变一个数的符号
2、用途:快速计算一个数除以2的n次方(8>>3 等同于8/2^3)

3、位运算技巧:
1)任何数和1进行&操作,得到这个数的最低位
1001
& 0001
———— 00012)想把某一位置0
11111111& 11111011
———— 11111011

位运算应用

#include <stdio.h>int main(int argc, const char * argv[]) {       int result = 9 & 8;     result = 9|8;    result = ~9;    result = 9^8;    printf("result = %d\n",result);    return 0;}

应用二

#include <stdio.h>int main(int argc, const char * argv[]) {    int result = 8<<2;    int b = 0b11000000000000000000000000000001;    result = -1073741823 << 2;    result = 9>>2;    printf("b = %d\n",b);    int c = 6;    result = c&1;    printf("result = %d\n",result);    return 0;}

利用位运算实现两个变量的值得交换

#include <stdio.h>void jiou(int n){      if (n&1) {        printf("奇数\n");    }else{        printf("偶数\n");    }}int main(int argc, const char * argv[]) {//    jiou(6);    int a = 3,b=4;    //a = 4,b = 3;    printf("a = %d,b = %d\n",a,b);//    int temp;  //    //3    3//    temp = a;//    //4    4//    a = b;//    //3    3//    b = temp;        a = a^b;    b = a^b;    a = a^b;    /*     0011   3     0100  ^     -----     0111     a  =  7     b=4     0111     0100  ^     -----     0011     b = 3, a = 7     a = a^b;     0111     0011  ^    ------     0100     a = 4     */    printf("a = %d,b = %d\n",a,b);    return 0;}

七、变量地址获取及存储原理
1、获取变量地址的方法
%p 输出一个地址 定义在函数中变量我们称为局部变量, 先分配字节地址大内存,然后分配字节地址小的内存
变量的首地址,是变量所占存储空间字节地址最小的那个地址

2、变量在内存中存储的原则
低位保存在低地址字节上,高位保存在高地址字节上
CPU能够识别存储单位就是字节

存储原理应用

#include <stdio.h>int main(int argc, const char * argv[]) {    int a = 3;       int b = 4;       char ch = 'a';    printf("&a = %p\n",&a);    printf("&b = %p\n",&b);    printf("&ch = %p\n",&ch);    return 0;}

学习心得:
通过本章知识点的剖析,了解了在计算机语言中,进制的概念以及转换的过程和原理 ,熟悉各进制之间的转换,一个数的源码,反码,补码的存在便于计算机的识别和计算,利用位运算改变数的符号,实现变量之间值得转换,了解变量的地址分配及占用的内存空间由高到低。

0 0
原创粉丝点击