正文开始
整数的二进制表示方法有三种:原码、反码和补码
三种表示方式均由符号位和数值位两部分构成。
符号位,即最高位,用0表示正数,用1表示负数
数值位,除去符号位剩余的部分都是数值位
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同:
例如:
对于整数来说,数据在内存中存放的是补码。原因在于,CPU中只有加法器,使用补码可以统一处理加减法,同时也可以将符号位和数值域统一处理。具体的原因请参考这篇文章>>>《原码、反码、补码 详解》,这篇文章思路很清晰。
超过一个字节的数据在内存中存储的时候,就会有存储顺序的问题,就比如十进制数字65224,将其转为二进制数字为1111 1110 1100 1000,存储它进内存,至少需要两个字节的空间,这两个字节存储內容的顺序又产生了分歧。所以我们按照不同的存储顺序,分为了大端字节序存储和小端字节序存储
例如,若一个变量的地址为0×0010,变量的值为0×1122
那么地址中0×0010为低地址,0×0011为高地址;
数据中0×11为高位字节內容,0×22为低位字节內容;
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit 位,但是在C语⾔中除了8 bit 的char之外,还有16 bit 的short型,32 bit 的int型,另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就产生了⼤端存储模式和⼩端存储模式
我们可以通过以下程序来判断当前机器的字节序:
#include
int check()
{
int i = 1;
return (*(char*)&i);
}
int main()
{
int ret = check();
if (ret == 1)
{
printf("小端字节序\n");
}
else
{
printf("大端字节序\n");
}
return 0;
}
解释:
变量 i 的类型为整型,大小为四个字节,十六进制表示为00 00 00 01。第六行代码中,将指向四个字节的指针强制类型转换为指向一个字节的指针(char 类型大小为一个字节),这样取到了这四个字节在低地址处存放的一个字节,若这个值为1,也就是低位存储在了低地址处,那么就是小端字节序;若这个值为0,也就是高位存储在低地址处,那么就是大端字节序
运行结果:


从运行结果和内存监视窗口我们也验证了目前我使用的机器是小端字节序。
常见的浮点数:2.453、1E10等,包括float、double、long double类型。我们可以通过查看float.h文件来查看浮点数表示的范围。
根据国际标准,任意一个二进制浮点数V可表示为如下形式:
V = (-1)S * M * 2E
例如:
十进制的5.0,写成二进制为101.0,标准形式为(-1)0 * 1.010 * 22,也就是说S=0,M=1.010,E=2
综上所述,我们不难看出,要想存储一个浮点数,只需要存储它的S,M,E,便能得到一个确切的二进制浮点数。
计算机中,对于32位的浮点数,最高的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M

对于64位的浮点数,最高的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

国际标准中对于有效数字M和指数E,还有一些特别的规定。
关于有效数字M
前面我们说过,有效数组M是一个大于1小于2的数,也就是说M的首位不变,都为1,M都为1.xxxxxxxx的形式。因此,可以将1省略掉,只保留后面xxxxxxxx的部分,这样就多出了一位的空间,也能够正确的存储数据。
关于指数E
首先我们要知道,指数E是一个无符号整数,也就是说,E只能表示一个正数,但我们知道,指数也是可以为负数的,那这应该怎么解决呢?
答案就是,取一个中间值,中间值前面的表示负数,中间值后面的表示正数。
对于8位的E,表示的范围是0-255,我们取中间值为127,也就是说0-126代表着负数,127代表着0,128-255代表着正数。比如当我们想要十次方时,E的值应该为10+127=137,我们想要-3次方,E的值就应该为(-3)+127=124。即10001001;对于16位的E,中间值就为1023。
指数E从内存中取出分为三种情况: