目录
整数在内存中的存储
整数二进制的三种表示
整数的二进制表示方法有三种:原码、反码、补码 ,三种表示方法均有符号位和数值位两部分。
其中最高位是符号位,用0表示正,1表示负。
整数在内存中存储的是二进制的补码形式,其中正整数的原码等于反码等于补码,而负整数的三种码各不相同。
二进制的三种表示方法:
**原码:**将数值按照正负的形式翻译成二进制的形式。
**反码:**将原码中除了符号位,其它的二进制位取反。
**补码:**将反码加1。
为什么整数在内存中存放的是其补码形式呢:
原理:
在计算机系统中,数值⼀律⽤补码来表⽰和存储。 原因在于,使⽤补码,可以将符号位和数值域统⼀处理; 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是 相同的,不需要额外的硬件电路
大小端字节序和字节序判断
超过一个字节的数据在内存中存储时,就有存储顺序的问题,存储顺序分为:大端字节序存储、小端字节序存储。
假设有一块内存如下:
内存中存放了一个整型数据(用16进制形式表示)
大端字节序存储 :数据的低位字节内容存储在内存的高地址处,而数据的高位字节内容存储在内存的低地址处。
小端字节序存储: 数据的低位字节内容存储在内存的低地址处,而数据的高位字节内容存储在内存的高地址处。
cpp
#include <stdio.h>
int main() {
int a = 0x11223344;
return 0;
}
在vs2022中运行上述代码,进入调试页面查看0x11223344在内存中的存储
我们可以发现,44是一个低位字节内容,存放在了低地址处,所以是小端存储模式。
那么采用哪种模式与什么有关呢?
采用大端存储(Big Endian)还是小端存储(Little Endian)与处理器架构和硬件设备有关。
一些处理器架构如 Motorola 68k、SPARC 等采用大端存储模式 ,一些处理器架构如 x86(Intel 和 AMD)、ARM 等采用小端存储模式。
不同的处理器架构和硬件设备可能采用不同的存储模式,因此在编程时需要考虑处理器的字节序,以确保数据在不同平台上的正确解释和交互。
在实际应用中,字节序问题可能会影响数据的传输和交换。例如,在网络通信中,不同设备之间需要互相传输数据,就需要考虑处理器的字节序,以确保数据的正确传输和解释。
整数在内存中存储相关的题目
题目1
请简述⼤端字节序和⼩端字节序的概念,设计⼀个小程序来判断当前机器的字节序。(10分)-百度笔试题
cpp
#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;
}
将i的地址类型转为char*类型的,解引用后只访问一个字节中的内容,所以拿出的可能是字节 00 或 字节 01,当为字节01时即是小端存储
题目2
cpp
#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;
}
结果为:a = -1, b = -1, c = 255
char 类型的数据取值范围是:-128 ~ 127 , unsigned char 类型的数据取值范围:0 ~ 255
在这里要先说明一点:在内存中数据的运算通常都是数值的补码形式进行运算的
char默认是signed char 类型,所以 signed char类型的变量存入 -1 时的变化如下图:
上述过程中整型提升的原因是:%d打印的是整数类型,要将char类型提升为int类型,所以将这个数值的补码形式进行高位的扩充至32位。
unsigned char 类型的变量存入整型-1在内存中的变化如下:
题目3
cpp
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
-128存入a时的变化如下:
题目4
cpp
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
解题如下:
题目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));
return 0;
}
(二进制以补码的形式进行加减1)
strlen统计\0(它的ASCII码值是0)之前的个数,-1到-128 有128个数,127到1有127个数,所以128+127=255,结果为255
题目6
cpp
#include <stdio.h>
unsigned char i = 0;
int main()
{
for (i = 0; i <= 255; i++)
{
printf("hello world\n");
}
return 0;
}
unsigned char 类型的数据范围在 0~255
255再加1就变为了0,造成了死循环
题目7
cpp
#include <stdio.h>
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2);
return 0;
}
所以ptr[-1]为4,用%x打印出的结果是0x4
假设a的地址为0x12ff40,(int)a表示将地址转化为了一个整数,加1变为0x12ff41,再强制类型转换为(int*)类型的地址,则地址0x12ff41对于地址0x12ff40是往后位移了一个字节的空间大小
*ptr2访问4个字节,从地址0x12ff41处往后找四个字节(上图中的红框),即00 00 00 02,所以用%x打印出的结果是0x02000000
浮点数在内存中的存储
根据国际标准IEEE 754,任意一个二进制浮点数V可以表示下面的形式:
例如:
**1、**十进制浮点数0.5的二进制浮点数是0.1(1的权重是2^-1次方,为0.5),S = 0,M = 1.0,E = -1,用上述的公式表示:(-1)^0 * 1.0 * 2^-1
**2、**十进制浮点数-5.5的二进制浮点数是-101.1,S = -1,M = 1.011,E = 2,相当于 (-1)^1 * 1.011 * 2^2
IEEE 754规定:
对于32位的浮点数(float),首位存S的值,往后走8位存E的值,剩下的23位存M的值。
对于64位的浮点数(double),首位存S的值,往后走11位存E的值,剩下的52位存M的值。
浮点数存的过程
E和M在内存中存储时比较特殊。
(以下均已32位的浮点数进行举例)
在内存中存储M时,小数点前的数默认为1,并且省略,只保存小数点后的数。比如1.01,只保存后面的01,补齐0到23位。
在内存中存储E时,如果E为8位,则它的取值范围是0~255,如果为11位,取值范围是0~2047
但公式中的E(科学计数法)是可以为负数的,所以IEEE 754规定,对于8位的E,它的值必须再加上127;对于11位的E,它的值必须再加上1023。对于32位的浮点数,当E为2时,它存储时为2+127 = 129,转为2进制为 1000 0001。
十进制浮点数5.5在内存中的存储为:
1、先将5.5转为二进制形式:101.1
2、101.1 = (-1)^0 + 1.011 * 2^2 ,通过公式我们可知S=0,E=2,M=1.011
3、S为0,M去掉小数点前的1,将011后面补0到23位即01100000000000000000000,E的值加127为129转为二进制存储为10000001
最后的结果为:
0 10000001 01100000000000000000000
浮点数取的过程
在内存中取出浮点数要分为三种情况
1、E不全为0或不全为1
0 10000001 01100000000000000000000
此浮点数的E不全为0也不全为1,这时,浮点数就采用下面的规则进行表示,首先第一位是S,即S=0。接着8位是指数E,10000001转为十进制减去127得到真实值,即E=2。后面的23位是M,将M的有效值011前面加上1,即M=1.011,因此取出的结果为 (-1)^0 * 1.011 * 2^2 ,运算后转为十进制为 5.5
2、E全为0
0 00000000 01100000000000000000000
此时的E全为0,则E等于1-127(1-1023) 即为真实值,即E = -126 ,有效数字M不再加上第一位的1,即M=0.011,取出的结果为:(-1)^0 * 0.011 * 2^(-126) ,结果是一个接近于0的数,用十进制小数表示就是0.000000
3、E全为1
0 11111111 01100000000000000000000
当E在内存中为全1时,11111111转为10进制为255减去127为128,M为1.011
结果为:(-1)^0 * 1.011*2^128 是一个非常大的一个数,它表示一个正无穷大,当S为1时它表示负无穷大。
浮点数题目
cpp
#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);
}
*pFloat的值:
num的值:
创作不易,看到这里麻烦请点一个免费的赞哟~~