整数
从二进制讲起:
1. 2进制中满2进1
2. 2进制的数字每⼀位都是0~1的数字组成
二进制转十进制 例如:1011(2)
怎么转换呢?从右向左看起:分别为:2^0,2^1,2^2,2^3……
那么1011(2) = 1 * 2^0 + 1 * 2 ^1 + 0 * 2^2 + 1 * 2 ^3 = 11
那么十进制如何转换为二进制呢?例如:125(10)
125去除2,舍去余数,用商继续除以2,直到商为0,将余数进行倒序排列,即得1111101
由此可以引出,数据在内存中的存储
在计算机内存中,整数的存储通常以二进制形式表示。通常情况下,整数在内存中以补码形式存储,即最高位表示符号位,0为正数,1为负数。
10进制的整数先转化为2进制的原码,不够32位(或64位)就补0。反码是符号位不变,其他位取反(即如果是0则取1,如果是1则取0),补码是反码加上1。整数以补码存放到内存中,正数的原反补码相同,负数需要经过转化为补码。
那为什么存放补码呢?
简化硬件设计和运算: 使用补码能够简化硬件设计和运算,因为加法和减法操作可以统一处理,无需额外区分正数和负数。这样可以减少逻辑门数量,提高运算效率。
唯一表示零: 在补码表示中,只有一个零的表示方式,即所有位均为0。这样可以避免正零和负零两种不同表示方式引起混乱。
方便进行运算: 补码能够简化加法、减法运算,使得计算机能够更方便地执行算术运算。
那么实际存储情况是什么样子呢?
注:在调试窗口观察内存,为了方便,通常为16进制|
0x12345678为32个比特位,4个字节,12为一个字节,34为一个字节,其他同理。
其实,数据内存中存储有两种--大端和小端,在vs2022环境下是小端存储。
大端(存储)模式:是指数据的低位字节内容保存在内存的⾼地址处,而数据的高位字节内容,保存在内存的低地址处。
小端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,而数据的高位字节内容,保存在内存的高地址处。
那如何去验证呢?我们知道,1的2进制为0000(31个0)1,我们取16进制得到:0x 0000 0001,如果是大端存储,即:0000 0001,如果是小端存储:0100 0000,所以,我们可以通过判断第一个字节数为1还是0来判断大小端。
int check(){
int i = 1;
return (*(char *)&i);
}
int main() {
int ret = check();
if(ret == 1) {
printf("⼩端\n");
}
else {
printf("⼤端\n");
}
return 0;
}
一些整数存储相关的题目
最后一个与大小端和指针相关
浮点数的存储
存储过程
对于32位的浮点数(float),最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
对于64位的浮点数(double),最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M
取出过程
1.
E不全为0或不全为1
指数E(取出的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
2.E(取出的时候)全为0,接近于0的很小的数字;E(存储时的E) + 127 == 0(取出时的E); E(存储时的E) == -127 1.XXXX * 2^(-127),这是一个很小的数字
3.E全为1(十进制255,即取出时的E),无穷大的数字 E(存储的E) + 127 == 255,E(存储是的E) == 128 1.XXXX * 2^128,这是一个很大的数字。那么看一个问题。