一、整数在内存中的存储
整数的二进制表示方法有三种:原码,反码,补码。
正整数的原码,反码,补码都相同,最高位为0(最高位是符号位)。
负整数的三种表示方法都不相同:原码表示整数的二进制,反码为原码的取反,补码为反码的+1,最高位为1(最高位为符号位)。
二、⼤⼩端字节序和字节序判断
大端字节序与小端字节序指的是数据在内容中是以什么形式进行存储的。
int main()
{
int a = 0x11223344;
return 0;
}
在这个代码中,a中内存的值为0x11223344
我们看见,在vs中内存中a的存储顺序是反着进行存放的。
1、什么是大小端
什么是大端模式:数据的低位字节内容保存在内存的高地址处,数据的高字节内容保存在低地址处
什么是小端模式:数据的低为字节内容保存在内存的低地址处,数据的高字节内存保存在高地址处
2、为什么会有大小端之分
简单来说就是为了适应不同的设备
练习1:
我们利用代码来判断自己的软件和设备是大端还是小端存储
法一:
int main()
{
int a = 0x11223344;
int* p = &a;
if (*p != 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
法二、
int check_sys()
{
int a = 1;
return (*(char*)&a);
}
int main()
{
int ret = check_sys();
if(ret == 1)
{
printf("小端\n");
}
else
{
printf("大端\n");
}
return 0;
}
输出:
练习2:
#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;
}
解析:
#include <stdio.h>
int main()
{
//00000000
//10000000000000000000000000000001 //内存中-1原码中存储格式
//11111111111111111111111111111110 //-1的反码
//11111111111111111111111111111111 //-1的补码
//11111111 //类型为char,取低地址8个比特,最高位为1
// 11111111111111111111111111111111 //进行整型提升,因为最高位为1所以都补1 此时为补码
//10000000000000000000000000000000 //此时为反码
//10000000000000000000000000000001 //原码
char a = -1;
signed char b = -1;
unsigned char c = -1;
//11111111111111111111111111111111 //-1在内存中补码存储格式
// 11111111 //类型为char类型,取低地址8个比特位,最高位为1
//00000000000000000000000011111111 //进行整型提升,因为c为无符号类型,所以补0 此时为补码
//00000000000000000000000011111111 //反码 最高位为0,是一个正整数,正整数的原反补的一样的
//00000000000000000000000011111111 //原码
printf("a=%d,b=%d,c=%d", a, b, c);
return 0;
}
输出:
练习3:
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
解析:
#include <stdio.h>
int main1()
{
//00000000
//10000000000000000000000010000000 //-128在内存中存储格式 原码
//11111111111111111111111101111111 //反码
//11111111111111111111111110000000 //补码
//10000000 //char类型,低地址取8个比特
//11111111111111111111111110000000 //%u为无符号打印一个整数,此时原反补是一样的,此时直接这样打印
char a = -128;
printf("%u\n", a);
return 0;
}
#include <stdio.h>
int main()
{
//00000000
//00000000000000000000000010000000 //128在内存中存储格式 原码
//00000000000000000000000010000000 //反码
//00000000000000000000000010000000 //补码
//10000000 //char类型,低地址取8个比特
//11111111111111111111111110000000 //%u为无符号打印一个整数,此时原反补是一样的,此时直接这样打印
char a = 128;
printf("%u\n", a);
return 0;
}
练习4:
#include <stdio.h>
int main()
{
char a[1000];
int i;
for (i = 0; i < 1000; i++)
{
a[i] = -1 - i;
}
printf("%d", strlen(a));
return 0;
}
有符号char类型的范围是-128——127,无符号char类型范围0——255。
a[i] = -1 - i; 当i等于0时,a[i]=-1,当i等于255的时候,那么a[i]=0。
输出:
练习5:
#include <stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
i为一个无符号的char类型,取值范围是0-255,在for循环中,i最大数为255,判断条件无法变成假,所以就会造成程序无限循环。
输出:
#include <stdio.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
}
return 0;
}
i为一个无符号int类型,所以i无法<0,造成程序循环
练习6:
#include <stdio.h>
//X86环境 ⼩端字节序
int main()
{
int a[4] = { 1, 2, 3, 4 };
int* ptr1 = (int*)(&a + 1); //取整个地址,整个地址+1
int* ptr2 = (int*)((int)a + 1); //a强制类型转换,字节+1
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
三、 浮点数在内存中的存储
浮点数跟整型二进制存储的格式是不一样的
根据国际标准,二进制浮点数的的公式为:
V = (-1)^s * M * 2^E
(-1)^s表示符号位,s等于0时为整数,为1时为负数
M表示有效数字,M是一个大于1小于2的数字。
2^E表示指数位
举例来说 十进制5,二进制写成101.0,相当于1.01 * 10^2
S=0 ,M=1.01 ,E=2
十进制-5,二进制写成-101.0 ,相当于-1.01 * 10^2
S=1,M=1.01,E=2
IEEE 754规定:
对于32位浮点数,最高位的1位存储S,接着8位存储E,剩余的23位存储M
对于64位浮点数,最高位的1位存储S,接着11位存储E,剩余的52位存储M
M是一个大于1小于2的数,在存储过程中,默认第一位总是为1,所以我们只存储小数点后面的位数,
E为一个无符号的整数,为了确保E不是一个负数,在浮点数进行存储时,需要E+127(32位机器)或者E+1023(64位机器)
1、E有0,E有1的情况下(正常情况)
十进制数位为9时,二进制数为1001,浮点数格式:1.001 * 10^3 ,S=0 , E=3 , M=001
E=3的二进制为:011,+127的二进制为10000010
0 10000010 00100000000000000000000
十进制等于1091567616
2、当E为全0的时候
此时0-127为-127,如果M=1.01时,那么将会是一个无限趋于0的数字
0 00000000 00100000000000000000000
3、当E为全1的时候
0 11111111 00010000000000000000000
此时E为一个无穷大的数
例题:
#include <stdio.h>
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;
}
当n等于9的时候,此时的内存存储的格式为一个整数格式,
00000000000000000000000000001001,此时E为全0,那么得到的数是一个无限趋近于0的数
*pFloat = 9.0;此时内存的存储格式变为浮点型的存储格式了
0 10000010 00100000000000000000000 整型进行读取的话,那么将是一个比较大的数字