内容导航
一、数据类型介绍
二、整型在内存中的存储:原码、反码、补码
1、二进制、八进制、十进制、十六进制
名称 | 介绍 | 举例 |
---|---|---|
二 进 制(Binary_system) | 逢2进1,由0和1两个数字组成。 | 01000001 |
八 进 制(Octal_number) | 逢8进1,由0-7数字组成,为了区分与其它进制的数字区别,开头都是以0(零)开始。 | 0101 |
十 进 制 (Decimalism) | 逢10进1,由0-9数字组成。 | 65 |
十六进制(Hexadecimal) | 逢16进1,由0-9和A-F组成,为了区分于其它数字的区别,开头都是以0x(零)开始。 | 0x41 |
2、进制间整数的相互转换
2.1十进制VS二进制:
2.1.1十进制转二进制:
原理:除以2,直到商为0,最后反向取余数。
举例:9(D)->1001(B)
2.1.2二进制转十进制:
原理:2为底数,权重为指数,乘以二进制位的累加。
举例:1001(B)->9(D)
2.2十进制VS八进制:
2.2.1十进制转八进制:
原理:除以8,直到商为0,最后反向取余数。
举例:99(D)->0143(o)
2.2.2八进制转十进制:
原理:8为底数,权重为指数,乘以八进制位的累加。
举例:0143(O)->99(D)
2.3十进制VS十六进制:
2.3.1十进制转十六进制:
原理:除以16,直到商为0,最后反向取余数。
举例:266(D)->0x10A(H)
2.3.2十六进制转十进制:
原理:16为底数,权重为指数,乘以十六进制位的累加。
举例:0x10A(H)-> 266(D)
2.4二进制VS八进制:
2.4.1二进制转八进制:
方法一:取三合一法
原理:三位二进制位合为一位八进制位,权重只有0、1、2。
举例:1001100(B)-> 114(O)
方法二:十进制转换
原理:二进制二进制先转换成十进制,再转化成八进制,方法同前。
2.4.2八进制转二进制:
方法一:取一解三法
原理:一位八进制位分解为三位二进制位(可以口算)。
举例:114(O) -> 1001100(B)
方法二:十进制转换
原理:八进制先转换成十进制,再转化成二进制,方法同前。
2.5二进制VS十六进制:
2.5.1二进制转十六进制:
方法一:取四合一法
原理:四位二进制位合为一位十六进制位,权重只有0、1、2、3。
举例:1001100(B)-> 4C(Ox)
方法二:十进制转换
原理:二进制先转换成十进制,再转化成十六进制,方法同前。
2.5.2十六进制转二进制:
方法一:取一解四法
原理:一位十六进制位分解为四位二进制位(一般可以口算)
方法二:十进制转换
原理:十六进制先转换成十进制,再转化成二进制,方法同前。
2.6八进制VS十六进制:
2.6.1八进制转十六进制:
方法:十进制转换
原理:八进制先转换成十进制,再转化成十六进制,方法同前。
2.6.2十六进制转八进制:
方法:十进制转换
原理:十六进制先转换成十进制,再转化成八进制,方法同前。
3、原码、反码、补码
计算机中的整数有三种二进制表示方式,即原码、反码和补码,三种表示方式均有符号位和数值位,符号位在最高位,用0表示正数,用1表示负数。
3.1正数的原码、反码、补码
介绍:正数的原码、反码、补码相同
举例:245(D)->0000 0000 0000 0000 0000 0000 1111 0101(B)(4个字节)
原码:0000 0000 0000 0000 0000 0000 1111 0101
反码:0000 0000 0000 0000 0000 0000 1111 0101
补码:0000 0000 0000 0000 0000 0000 1111 0101
3.2负数的原码、反码、补码
介绍:负数的原码、反码、补码各不相同
原码:直接按照规则转换成二进制即可;
反码:原码符号位不变,其余位按位取反;
补码:反码加1得到补码。
举例:-8(D)-> 1000 0000 0000 0000 0000 0000 0000 1000 (B)
原码:1000 0000 0000 0000 0000 0000 0000 1000
反码:1111 1111 1111 1111 1111 1111 1111 0111
补码:1111 1111 1111 1111 1111 1111 1111 1000
3.3原码、补码的相互转换
方法一:
方法二:
4、整型在内存中的存储
数据在内存中存放的是补码(打印是打印数据的原码),原因在于使用补码可以将符号位和数值域统一处理,同时加法和减法也可以统一处理(CPU只有加法器),此外,补码与原码的相互转换,其运算过程是相同的,不需要额外的硬件电路。
用VS观察负数在内存中的存储:
举例:-8(D)-> 1000 0000 0000 0000 0000 0000 0000 1000 (B)
原码:1000 0000 0000 0000 0000 0000 0000 1000
反码:1111 1111 1111 1111 1111 1111 1111 0111
补码:FFFFFFF8
截图:所以验证了数据在内存中存放的是补码。
三、大小端字节序介绍及判断
1、为何有大端和小端
拿int数据类型举例,一个int数据占4个字节,分别将4个字节放入内存的方法各不相同,按照前后顺序一次存入符合逻辑,现在看来顺序放置是具备协调美的(嘿嘿),由于数据有正反顺序,所以导致数据在内存中的存放也分为两种模式,科学家给它们命名为“大端存储模式”和“小端存储模式”。
2、什么是大端和小端
大端模式:数据的低位保存在内存的高地址中,数据的高位保存在内存的高地址中。
如图所示:
小端模式:数据的低位保存在内存的低地址中,数据的高位保存在内存的低地址中。
如图所示:
3、怎么判断大端小端
解释:利用强制类型转换,将占4个字节的整型变量a=1存入内存,1在最低位,强制用char*类型的指针强制往后访问一个字节,如果解引用强制访问的这个字节等于1,说明是低位数据往低地址存放,为小端存储,如果不等于1,说明低位数据存放在高地址去了,为大端存储。
代码:
#include <stdio.h>
int check_sys()
{
int i = 1;
return (*(char *)&i);
}
int main()
{
int ret = check_sys();
if(ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
四、有关数据打印的例子
1、代码例子一:
//输出什么?
#include <stdio.h>
int main()
{
char a= -1;
signed char b=-1;
unsigned char c=-1;
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
过程解析:
2、代码例子二:
//输出什么?
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a);
return 0;
}
过程解析:
3、代码例子三:
//输出什么?
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a);
return 0;
}
过程解析:
4、代码例子四:
#include <stdio.h>
int main()
{
int i= -20;
unsigned int j = 10;
printf("%d\n", i+j);
return 0
}
//按照补码的形式进行运算,最后格式化成为有符号整数
过程解析:
5、代码例子五:
//输出什么?
#include <stdio.h>
int main()
{
unsigned int i;
for(i = 9; i >= 0; i--)
{
printf("%u\n",i);
}
return 0;
}
过程解析:
signed int的范围为:
正数:00000000 00000000 00000000 00000000->01111111 11111111 11111111 11111111负数:11111111 11111111 11111111 11111111->10000000 00000000 00000000 00000000
正数: 0->7F FF FF FF
负数:-7F FF FF FF->0
图示如下:
unsigned int的范围为:00 00 00 00->FF FF FF FF->00 00 00 00
五、浮点型在内存中的存储
1、浮点数二进制转换规则
整数部分:整数部分除以2取余101。
小数部分:小数部分乘以2取整.1。
如图:
2、浮点数存储规则
举例:
3、IEEE 754规定
对于32位的浮点数,最高的1位是符号位S,接着的8位是指数E,剩下的23位为有效数字M。
如图:
对于64位的浮点数,最高的1位是符号位s,接着的11位是指数E,剩下的52位为有效数字M。
如图:
4、指数E的规则
存入内存:E+127/1023后转为二进制
取出内存:
1、E不全为0或不全为1:即指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位的1。
2、E全为0:浮点数的指数E等于1-127=-126(或者1-1023=-1022)即为真实值,有效数字M不再加上第一位的1,而是还原为0.xxxxxx的小数。
3、E全为1:如果有效数字M全为0,表示±无穷大(正负取决于符号位s)。
5、举例介绍
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
*pFloat = 9.0;
printf("num的值为:%d\n",n);
printf("*pFloat的值为:%f\n",*pFloat);
return 0;
}
过程解析: