整数在内存中的翻译
整数的二进制表示方式有3种,即原码,反码,补码
在内存中存放的是补码

类型存入翻译和类型取出翻译,数据存储方式和数据取出方式,都是同操作流程的相反顺序
在讲翻译前需要引入个概念 符号位
符号位表示的就是 数据在正负符号
例如:9 其实是 +9 (常常省略+号) -9
所以在32个比特位最前方一位表示为符号 0正 1符负
现讲,整形类型的翻译方式
整形的翻译方式会根据,整形的正负数分两类
正数:
正数的原码是本身的二级制
正数特殊的点在于 原码 反码 补码 都相同
例如:1的2进制(int为4字节,有32个比特位)
0 0000000 00000000 00000000 00000001
负数:
负数的原码也是本身二进制**(正负原码翻译的没区别)**
反码为 符号为不变,其它位0变1,1变0
补码为 在反码的基础上+1
例如:-1的全流程图如下

负数取出数据就是 -1 再 符号位不变 0变1,1变0;只不过顺序流程倒置而已
不过取出 将补码 符号位不变 0变1 1变0 再+1也能得到原码
注意上面说的是两个方式,选一个就可以得到原码
数据在内存中的存放
我们常常会发现,数据在内存中存放是按比例反向的
我们去观察以下代码在内存中单存放
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
int a = 0x11223344;
return 0;
}


能发现,这里的存放是按字节为大小,反向存放着。这样的存放方式就叫做小端字节序
大小端字节序
其实超过一个字节的数据在内存中存储的时候,就会有存储顺序的问题。按照不同的存储顺序,我们分为大端字节序和小端字节序存储
字节序存储 按照一个字节一个字节的大小分开数据,按某种顺序存储
这个顺序的分辨在与小端和大端
小端字节序:
将低位字节的内容存储到低地址处,高位字节的内容存储到高地址处
例如:
123 可以分出 个位3 十位2 百位1
个位低位 百位为高位
而数据会翻译成补码
再以一个字节大小分出高低位,分别存放

大端字节序:
讲低位字节内存存储到高位地址处,高位字节序内容存储到低地址处

**问题:**设计一个小程序来判断当前机器的字节序
cpp
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int test()
{
int a = 1;
char* p = &a;
return *p;
}
int main()
{
if (test() == 1)
printf("小端");
else
printf("大端");
return 0;
}
题目2:
cpp
#include <stdio.h>
int main()
{
char a= -1; // -1 VS. char是signed char 这个取决于编译器
signed char b=-1; // -1
unsigned char c=-1; // 255
printf("a=%d,b=%d,c=%d",a,b,c);
return 0;
}
cpp
unsigned char c=-1;
printf("%d",c);
结果为255的过程如下图判断

问题3:
cpp
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n",a); // 4294967168
return 0; // 11111111 11111111 11111111 10000000
}
问题4:
cpp
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n",a); // 4294967168
return 0; // 11111111 11111111 11111111 10000000
}
128和-128在截取时都是1000 0000 后续操作一样值一样
问题5:
cpp
#include <stdio.h>
int main()
{
char a[1000];
int i;
for(i=0; i<1000; i++)
{
a[i] = -1-i;
}
printf("%d",strlen(a)); // 255
return 0;
}
这里有个结论图:

问题5:
cpp
#include <stdio.h>
//X86环境 ⼩端字节序
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1); // 0x00 00 00 04 0x 02 00 00 00
printf("%x,%x", ptr1[-1], *ptr2); // 4 2000000
return 0;
}
浮点数在内存中的存储
任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式
V = (-1)^S * M * 2^E
• (-1)^S 表⽰符号位,当S=0,V为正数;当S=1,V为负数
• M表⽰有效数字,M是⼤于等于1,⼩于2的
• 2^E 表⽰指数位
举例来说:
⼗进制的5.0,写成⼆进制是 101.0 ,相当于 1.01×2^2
那么,按照上⾯V的格式,可以得出S=0,M=1.01,E=2
观察上方式子可以发现,(-1) 和 2是固定常数,变化的位 S M E 三数所以存储只需要储存S M E 就好了
在存储 S M E 3数时还需要注意2点:
1.由于 M 数 总是会变化成 1.xxxx的数,范围在(1,2)之间
所以再存储时可以将1.xxxx的1不进行存储,在有效位存储时会多出1位
2.将举例改为0.5时会发现E 会出现负数情况,所以 E在存储时会根据类型的不同做出一下措施:
1.32位 E+127(中间值)
2.64为 E+1023(中间数)
这中间数和E在内存中存储的内存空间大小相关
现在储存内容弄清后,接下来就是每个内容有多大存储空间
由国家标准规定:
32位( float 4字节):

64位( double 8字节)
浮点数取的过程 指数E从内存中取出还可以再分成三种情况:
E不全为0或不全为1 :
这时,浮点数就采⽤下⾯的规则表⽰,即指数E的计算值减去127(或1023),得到真实值,再将有效 数字M前加上第⼀位的1。 ⽐如:0.5的⼆进制形式为0.1,由于规定正数部分必须为1,即将⼩数点右移1位,则为1.0*2^(-1),其 阶码为-1+127(中间值)=126,表⽰为01111110,⽽尾数1.0去掉整数部分为0,补⻬0到23位 00000000000000000000000,则其⼆进制表⽰形式为:
0 01111110 00000000000000000000000
E全为0:
这时,浮点数的指数E等于1-127(或者1-1023)即为真实值,有效数字M不再加上第⼀位的1,⽽是还 原为0.xxxxxx的⼩数。这样做是为了表⽰±0,以及接近于0的很⼩的数字;
- 这相当于指数被固定为最小的值(-126),然后只通过尾数部分来提供更精细的精度
0 00000000 00100000000000000000000
E全为1:
这时,如果有效数字M全为0,表⽰±⽆穷⼤(正负取决于符号位s);
0 11111111 00010000000000000000000
问题:
cpp
#include <stdio.h>
int main()
{
int n = 9;
float *pFloat = (float *)&n;
printf("n的值为:%d\n",n); // 9
printf("*pFloat的值为:%f\n",*pFloat); // 0.000000
*pFloat = 9.0;
// 0 1000 0010 001 0000 00000000 00000000
printf("num的值为:%d\n",n); // 1091567616
printf("*pFloat的值为:%f\n",*pFloat); // 9.000000
return 0;
}
