一.原码,反码,补码
对于无符号数,原码反码补码相同
原码 反码 补码
三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同
①原码
直接将二进制按照正负数的形式翻译成二进制就可以
②反码
//将原码的符号位不变,其他位依次按照取反就可以得到了
③补码
//在反码的基础上加1
int main()
{
int a = 20;
//00000000000000000000000000010100 --原码
//00000000000000000000000000010100 --反码
//00000000000000000000000000010100 --补码
//转化为16进制位
//0x00000014 在VS的编译器中他的存储方式是小端字节序
int b = -10;
//1000000000000000000000001010 -- 原码
//1111111111111111111111110101 -- 反码
//1111111111111111111111110110 --补码
//0xFFFFFFF6
}
对于整形来说:数据存放内存中其实存放的是补码
为什么呢?
1.在计算机系统中,数值一律用补码来表示和存储。原因在于使用补码,可以将符号位和数值域同时处理;同时,加发和减法也可以同时处理,并且在CPU中只有加法器
2.那你就会说1-1是不是就没法计算了呢?
转换为1+(-1)
二.大小端介绍
大端存储模式:是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中;
小端存储模式:是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中;
对于VS编译器来说,是小端存储模式,且左边为低地址,右边为高地址 低----------------高
思考题:设计一个小程序来判断当前机器的字节序
解析:我们拿出一个整数的第一个字节,比如int a = 1 0x00000001
大端模式 00 00 00 01
小端模式 01 00 00 00
如果是00表示大端 , 是01表示小端
这里封装一个函数来判断当前机器的大小端
int check_sys()
{
int a = 1;
char* p = (char*)&a;
//返回1表示小端
//返回0表示大端
return *p;
}
int main()
{
int a = 1;
char* p = (char*)&a; //char* 能表示我当前访问的自己大小
int ret = check_sys();
if (ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
思考题2.
输出什么?
int main()
{
//10000000000000000000000000000001
//11111111111111111111111111111110
//11111111111111111111111111111111
char a = -1;
//11111111
//应为打印的是%d所以这里要发生整形提升,对于char来说是有符号的
//所以前面补符号位
//11111111111111111111111111111111 -- 补码
//原码就是-1
signed char b = -1;
//11111111
//和char的性质一样
unsigned char c = -1;
//11111111 最前面的并不是符号位,所以发生整形提升的时候补充0
//0000000000000000000110011111111
//所以对应的十进制数就是255
printf("a = %d,b = %d,c = %d", a, b, c);
return 0;
}
//结果是 -1 -1 255
思考题3.
输出什么?
int main()
{
char a = -128;
//10000000000000000000000010000000
//11111111111111111111111101111111
//11111111111111111111111110000000
//发生截断
//10000000
//11111111111111111111111110000000--补码
//但是对于一个无符号数来说,原反补是相同的
//所以a = 4294967168转换为无符号十进制数 是一个很大的数字
printf("%u\n", a); //%u--打印十进制的无符号数
return 0;
}
对与一个char的范围是
0-127 -1 — -128 这个可以表示为一个圆盘左边部分从上到下是-1 —> -128 右边从下到上是127 --> 0
整体的范围是-128 --> 127
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
//这里你要思考对于一个char类型能存储下一个128吗?
int main()
{
char a = 128; //127 + 1 根据上面的圆盘就知道其实也是打印出来-128的意思
printf("%u\n", a);
return 0;
}
按照补码的形式进行运算,最后格式化成为有符号整数
int main()
{
int i = -20;
unsigned int j = 10;
//10000000 00000000 00000000 00010100
//11111111 11111111 11111111 11101011
//11111111 11111111 11111111 11101100 -- -20补码
//00000000 00000000 00000000 00001010 -- 10的补码
//11111111 11111111 11111111 11110110 --结果
//11111111 11111111 11111111 11110101 -- 结果的补码
//10000000 00000000 00000000 00001010 -- 结果原码 -10
printf("%d\n", i + j);
}
结果是什么?
#include<windows.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
Sleep(100);// 单位是ms 也就是0.1s
}
return 0;
}
//你会发现对于一个unsigned int 类型的压根就不可能小于0,所以这是一个死循环
经典题
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
//结果 255 因为对于char 来说-128 --> 127 的范围,你好好想一下刚才的圆盘-128 -1 = -129 转换过来就是127
//知道他从右下转到右上遇见了字符'0' ,他就停止了
错误想法:char类型的a定义的数组中存放的是-1,-2 …-1000,但是strlen遇不见\0 所以strlen的大小是一个随机值
unsigned char类型题目
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
结果也会是死循环 因为unsigned char 的大小最大也只是255,所以一直再循环体内部满足条件,就一直打印"hello world"
三.浮点型在内存中的存储
int main()
{
int n = 9;
float* pFloat = (float*)&n;// float* 访问的也是4个字节的空间大小
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;
}
解析:pFloat 这个指针来说,它认为int = 9 在内存中存储的补码应该是浮点类型的
00000000 00000000 00000000 00001001
0 00000000 00000000000000000001001
还原回来:(-1)^ 0* 0.00000000000000000001001 * 2^-126
无限接近0,所以打印出来是0.000000
*pFloat = 9.0的存储形式是
(-1)^ 0 * 1.001 * 2^3 然后再把它存到内存中 M=3加127 转化为二进制
0 10000010 00100000000000000000000 – 计算值认为这个就是补码,且符号位表示正。
注意事项:
32位的情况:
int main()
{
float f = 5.5;
//5.5
//101.1
//(-1)^0 * 1.011 * 2^2
//S=0
//M = 1.011
//E =2
//E在内存中真正的存储方式是要加127的 把129转化为二进制数
// 0 10000001 011 00000000000000000000(补齐23位M)一共32位,这才是真正的在内存中存储的二进制序列
//0x 40 b0 00 00 以16进制的形式展现内存
}
64位情况
指数E从内存中拿出来的情况:
1.对于E不为全0或不为全1的情况下:对于32位需要-127,对于64位需要-1023才能得到它真正的E值
2.E为全0情况:对于这种情况你要想他已经加了127结果还全为0,说明原来是-127,这是一个非常小的数
0 00000000 01100000000000000000000
0.011 * 2^-126
对于E为全0的情况我们规定在还原的时候M不需要在补1,E也直接改为固定值1-127
3.E为全1的情况:E+127 = 255,所以原来E=128
1.xxx * 2^128 这个数太大了,计算不了,所以也不考虑了。