对于进制,我们都很熟悉,从小学开始就知道 1、2…9、10、11… 这就是十进制。 几进制就是逢几进1。
为什么全世界各地都从一开始就习惯使用 10 进制,很简单,因为我们有10个手指头,哈哈哈哈哈 直接数指头就行了!
那么对于计算机来说,它并没有手指,它处理数据是根据2进制来处理的! 二进制:010101…0101 。 那么为什么是 2进制 呢? 因为机器处理指令的硬件都是双态的,只要是涉及到数据的,那么就是 电位的 “高” 或 “低”,即二进制的 “1” 或 “0”。
在程序猿使用机器语言来编写程序的时候,二进制太麻烦,为了方便会使用 八进制 或 十六进制。谈到机器语言的话,跟十进制就没啥关系了!
除2取余, 余数倒序; 得到的序列就是二进制表示形式
将每个数值进行标记,从右往左,从0开始进行标记,依据之前进行的标记,以2为底(有值就是2没值就是0),并以标记数进行开次方 ,最后,将所得的数相加
三个二进制位代表一个八进制位, 因为3个二进制位的最大值是7,而八进制是逢8进1
列: 每三个数字为一组,若不足三位,则在前用“0”补足(若是小数,则在后面补足3位),将分过组的二进制数转化成八进制数
将八进制数变更成二进制数,第一位若是“0”,请舍去(小数的话,最后一位,如果是“0”,请舍去)将所有数字进行组合,得出最终数字
四个二进制位代表一个十六进制位,因为4个二进制位的最大值是15,而十六进制是逢16进1
列: 每四个数字为一组,若不足四位,则在前用“0”补足(若是小数,则在后面补足4位), 将分过组的二进制数转化成十六进制数
将十六进制数变更成二进制数,第一位若是“0”,请舍去(小数的话,最后一位,如果是“0”,请舍去)将所有数字进行组合,得出最终数字
整数部分,直接转换为二进制即可, 小数部分,使用"乘2取整,顺序排列" 用2乘十进制小数,可以得到积,将积的整数部分取出,再用2乘余下的小数部分,直到积中的小数部分为 零,或者达到所要求的精度为止然后把取出的整数部分按顺序排列起来, 即是小数部分二进制最后将整数部分的二进制和小数部分的二进制合并起来
以0.65为例
0.65x2=1.3,取1;
0.3x2=0.6,取0;
0.6x2=1.2,取1;
0.2x2=0.4,取0;
0.4x2=0.8,取0;
0.8x2=1.6,取1;
0.6x2=1.2,取1;
此时已经陷入了循环,不必再计算,0.65的二进制就是01010011……,有的计算中并不要求有符号位,可省略,为1010011……
二进制的小数转换为十进制主要是乘以2的负次方,从小数点后开始,依次乘以2的负一次方,2的负二次方,2的负三次方等。''例如二进制数0.001转换为十进制。
第一位为0,则0*1/2,即0乘以2负 一次方。
第二位为0,则0*1/4,即0乘以2的负二次方。
第三位为1,则1*1/8,即1乘以2的负三次方。
各个位上乘完之后,相加,0*1/2+0*1/4+1*1/8得十进制的0.125
计算机只能识别0和1, 所以计算机中存储的数据都是以0和1的形式存储的,数据在计算机内部是以补码的形式储存的, 所有数据的运算都是以补码进行的,正数的原码
原码 : 最高位是符号位,0代表正数,1代表负数,非符号位为该数字绝对值的二进制。
x=1100110,则[X]原=01100110,
x=-1100111,则[X]原=11100111,
反码: 正数的反码与原码一致,负数的反码是对原码按位取反,只是最高位(符号位)不变。
x=1100110,则[X]反=01100110,
x=-1100111,则[X]反=10011000,
补码: 正数的补码与原码一致,负数的补码是对原码按位取反加1,符号位不变。
x=1100110,则[X]补=01100110,
x=-1100111,则[X]补=10011001,
为何要使用原码, 反码和补码
首先, 因为人脑可以知道第一位是符号位, 在计算的时候我们会根据符号位进行加减。 但是对于计算机, 加减乘数已经是最基础的运算,,设计得尽量简单。计算机辨别"符号位"显然会让计算机的基础电路设计变得十分复杂! 于是人们想出了将符号位也参与运算的方法.。我们知道,根据运算法则减去一个正数等于加上一个负数,即: 1-1 = 1 + (-1) = 0 ,所以机器可以只有加法而没有减法, 这样计算机运算的设计就更简单了。
我们来看原码的相加减,如下:
计算十进制的表达式: 1-1=0
二进制的表达式:1 - 1 = 1 + (-1) = [00000001]原 + [10000001]原 = [10000010]原 = -2
如果用原码表示,让符号位也参与计算,显然对于减法来说,结果是不正确的。这也就是为何计算机内部不使用原码表示一个数。为了解决原码做减法的问题,
出现了反码,如下所示:
计算十进制的表达式:1-1=0,
二进制的表达式:1 - 1 = 1 + (-1) =[0000 0001]反 + [1111 1110]反 = [1111 1111]反 = [1000 0000]原 = -0
发现如果用反码计算减法,结果是正确的。而唯一的问题其实就出现在"0"这个特殊的数值上。虽然人们理解上+0和-0是一样的,但是0带符号是没有任何意义的。而且会有[0000 0000]原和[1000 0000]原两个编码表示0。于是补码的出现, 解决了0的符号以及两个编码的问题。
1-1 = 1 + (-1) = [0000 0001]补 + [1111 1111]补 = [0000 0000]补=[0000 0000]原
这样0用[0000 0000]表示, 而以前出现问题的-0则不存在了
效率高,内存消耗少, 在某些情况中,位操作可以避免或者减少在一个数据结构上需要进行循环的次数,并且可以成倍的效率提升,因为位操作是并行处理的。但是位操作的代码比较难以编写和维护。
程序中的所有数据在计算机内存中都是以二进制的形式储存的。位运算就是直接对整数在内存中的二进制位进行操作,C语言提供了6个位操作运算符, 这些运算符只能用于整型操作数
使用规则:两个二进制操作数对应位同为1 结果位才为1,其余情况为0;
使用规则:两个二进制操作数对应位只要有一个为1结果位就为1,其余情况为0;
使用规则:两个二进制操作数对应位相同为0,不同为1;
使用规则:一个二进制操作数,对应位为0,结果位为1;对应位为1,结果位为0;
这里稍微有些麻烦,做下解释: 十进制 1 的二进制表示为0000 0001
每位都取反为1111 1110
这是内存中的保存形式。我们读取的十进制是根据原码来读取,而在内存中,数值都是以二进制补码形式存储的。正数的补码和原码一样,
负数的补码得到过程:原码转反码再转补码,负数的补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1
偶数: 的二进制是以0结尾 8 -> 1000 10 -> 1010
奇数: 的二进制是以1结尾 9 -> 1001 11 -> 1011
任何数和1进行&操作,得到这个数的最低位
1000 &0001 ----- 0000 // 结果为0, 代表是偶数
1011 &0001 ----- 0001 // 结果为1, 代表是奇数
enum Unix {
S_IRUSR = 256,// 100000000 用户可读
S_IWUSR = 128,// 10000000 用户可写
S_IXUSR = 64,// 1000000 用户可执行
S_IRGRP = 32,// 100000 组可读
S_IWGRP = 16,// 10000 组可写
S_IXGRP = 8,// 1000 组可执行
S_IROTH = 4,// 100 其它可读
S_IWOTH = 2,// 10 其它可写
S_IXOTH = 1 // 1 其它可执行
};
假设设置用户权限为可读 可写printf("%d\n", S_IRUSR | S_IWUSR); // 384 // 110000000
a = a^b; b = b^a; a = a^b;
按位左移: 把整数a的各二进位全部左移n位,高位丢弃,低位补0 由于左移是丢弃最高位,0补最低位,所以符号位也会被丢弃,左移出来的结果值可能会改变正负性
规律: 左移n位其实就是乘以2的n次方
2<<1; //相当于 2 *= 2 // 4
0010<<01002<<2; //相当于 2 *= 2^2; // 8
按位右移: 把整数a的各二进位全部右移n位,保持符号位不变为正数时, 符号位为0,最高位补0为负数时,符号位为1,最高位是补0或是补1(取决于编译系统的规定)
规律: 快速计算一个数除以2的n次方
2>>1; //相当于 2 /= 2 // 1
0010>>00014>>2; //相当于 4 /= 2^2 // 1
内存模型是线性的(有序的)
对于 32 机而言,最大的内存地址是2^32次方bit(4294967296)(4GB)
对于 64 机而言,最大的内存地址是2^64次方bit(18446744073709552000)(171亿GB)
CPU 在运作时要明确三件事:
如何明确这三件事情:
地址总线: 地址总线宽度决定了CPU可以访问的物理地址空间(寻址能力)
数据总线: 数据总线的位数决定CPU单次通信能交换的信息数量
控制总线: 用来传送各种控制信号
char是C语言中比较灵活的一种数据类型,称为“字符型” , char类型变量占1个字节存储空间,共8位除单个字符以外, C语言的的转义字符也可以利用char类型存储
char型数据存储原理: 计算机只能识别0和1, 所以char类型存储数据并不是存储一个字符, 而是将字符转换为0和1之后再
存储正是因为存储字符类型时需要将字符转换为0和1, 所以为了统一, 老美就定义了一个叫做ASCII表的东东ASCII表中定义了每一个字符对应的整数
char ch1 = 'a';
printf("%i\n", ch1); // 97
char ch2 = 97;
printf("%c\n", ch2); // a
char类型注意点
char c = '我'; // 错误写法
char ch = 'ab'; // 错误写法
char ch1 = '6'; // 存储的是ASCII码 64
char ch2 = 6; // 存储的是数字 6
首先要明确的:signed int等价于signed,unsigned int等价于unsigned, signed和unsigned的区别就是它们的最高位是否要当做符号位,并不会像short和long那样改变数据的长度,即所占的字节数。
signed:表示有符号,也就是说最高位要当做符号位。但是int的最高位本来就是符号位,因此signed和int是一样的,signed等价于signed int,也等价于int。signed的取值范围是-2^31 ~ 2^31- 1
unsigned:表示无符号,也就是说最高位并不当做符号位,所以不包括负数。因此unsigned的取值范围是:0000 0000 0000 0000 0000 0000 0000 0000 ~ 1111 1111 1111 1111 1111 1111 1111 1111
,也就是0 ~ 2^32 - 1
修饰符号的说明符可以和修饰长度的说明符混合使用, 相同类型的说明符不能混合使用
signed short int num1 = 666; //正常
signed unsigned int num2 = 666; // 报错
点赞 -收藏-关注-便于以后复习和收到最新内容有其他问题在评论区讨论-或者私信我-收到会在第一时间回复感谢,配合,希望我的努力对你有帮助^_^
免责声明:本文部分素材来源于网络,版权归原创者所有,如存在文章/图片/音视频等使用不当的情况,请随时私信联系我。
版权说明 : 本文为转载文章, 版权归原作者所有 版权申明
原文链接 : https://huanmin.blog.csdn.net/article/details/125684150
内容来源于网络,如有侵权,请联系作者删除!