C语言基本数据类型的存储

前言

学习C语言时,我对于C语言基本数据类型不太懂。后来学习计组之后,了解了计算机内部数据的存储。这篇文章将从底层,剖析基本数据类型在计算机中是如何存储。

整型数据的表示方法

在计算机中,数据以二进制的方式存储,即我们平时所使用的十进制数,都会被转化为0101等数据。如十进制的12,转化成二进制就是1010。
我平时习惯将四个二进制数写在一起,第一,便于书写时一眼能看清位数;第二,也便于二进制与16进制的转换。
比如十进制数99,我会先看成64+32+2+1,因此转换成二进制数的时候,就是0110 0011。要记得常见的2的几次方,比如2的0次方等于1, 2的十次方等于1024。

计算机的主存储器是由一个个存储0和1的存储元件组成,每个存储元里面存储的一个二进制数,我们成为1bit 。我们常用的计算机中,一般是8个存储元为一组,存储的8个二进制数为1B(字节)。

参与运算的机器数有两种,一种是无符号数,一种是有符号数。
无符号数中,整个机器字表示的二进制位均表示数值。比如计算机中存储了机器数1000 0001,即表示十进制数129。当我们在C语言中某个数据类型前加入unsigned时,表示该数为无符号数。存储的时候,首位就是数值位。比如 存储129,且该计算机是8位计算机,那么在计算机中存储的就是1000 0001。
对于有符号数,计算机中最高位,即最前面的那一位表示符号。0表示该数为正数,1表示该数为负数。
对于有符号数的表示,有四种方式。原码、补码、反码、移码。
我们先不必在意这四个码分别是什么。
我们只需要知道,我们常用的计算机,一般都是以补码存储。
因此,我们先介绍原码和补码。为了便于举例,我们假设某个计算机是8位计算机。
127转换成二进制是多少呢——0111 1111。那-127呢?如果直接转换,根据之前所讲的首位为1则为负数,我们很容易得到1111 1111。
是的,这就是原码。我们不必死扣概念,知道这个例子即可。也就是说,正数和负数之间的差别,其实仅仅是首位的符号位。
但是,在计算机中存储的,并不是原码,而是补码。(为什么?感兴趣的可以查一下相关的资料)
对于补码而言,其正数与原码的表示方式完全相同。也就是说,127,在计算机中存储的,其实就是0111 1111。那-129呢?先给结论,-127是以1000 0001存储的。
是不是没有找出规律?
那请把目光返回到我讲补码时的1111 1111。其实,负数的补码就是将原码的符号位不变,数值位全部取反,最后在末位+1,因此,我们就得到了-127的补码——1000 0001。
发现了没有,无符号数129和有符号数的-127的存储,都是1000 0001。
理解了这两种码。那在C语言中,int,short int,long,long long仅仅是位数上的差别。
需要注意的是,32位机器中, int 是4字节,short int 是2字节,long 是4字节,long long是8字节。
执行以下代码,我们可以得到结果。

int main()
{
    
    
	printf("sizeof_int= %d \n", sizeof(int));
	printf("sizeof_short= %d \n", sizeof(short));
	printf("sizeof_long= %d \n", sizeof(long));
	printf("sizeof_long long= %d \n", sizeof(long long));
}

在这里插入图片描述

浮点型数据的存储

对于浮点数的存储,目前遵循一个标准——IEEE 754标准。
该标准中,将数据分为以下几部分。
数符、阶码部分、尾数部分。
我们先举一个十进制的例子。1001用科学计数法怎么表示?
——1.001×10^4。
这里的4指的就是阶码,因为是十进制,因此10为底,而1.001,就是尾数。
比如9,转化成二进制就是1001,那用科学计数法表示,就是1.001×2^0011。0011就是十进制的3,此时要写成二进制。
以float为例,数符即表示该数的符号,存储在最高位,占1bit。阶码是中间的8位,尾数则是后面的23位。这是规定,知道即可。
因此,float在32位机器中,占32bit,即4B。
注意,表面上是23位,实际上这23位都是小数点后的23位。小数点前面的1被隐含了。
比如上面的9的尾数,1.001,在存储的时候只存储001,前面的1被隐含了。
在我们上面举的例子中,尾数部分决定了一个数的精确度。也就是说,float尾数实际精确度为24位。

为什么要强调这一点?
比如我们要将int转换成float,那有没有可能出现精度丢失?答案是肯定的。int可以保留32位精度,而float只能保存24位,因此是可能出现精度丢失的。
我们给出如下代码

int main()
{
    
    
	printf("sizeof_float= %d \n", sizeof(float));
	printf("sizeof_double= %d \n", sizeof(double));

}

在这里插入图片描述
可以看出,double需要用8B存储。根据IEEE 754标准,double保存精度的位数为52+1位(+1同float),即将int转化为double时,不会出现精度丢失。

注意:float和double在存储一些小数时,无法实现精确存储。比如,小数点后,可以精确的是0.5, 0.25,0.125,0.75等。而对于2.323,1.332这类数,计算机是无法精确存储的。因此,在判断语句中,我们不能判断两个小数数据是否相等。
如下列代码是不规范的。

double a ,b;
...
if (a == b)

字符型的存储

int main()
{
    
    
	printf("sizeof_char= %d \n", sizeof(char));
}

在这里插入图片描述
可以看出,char型在内存中占1B。
char型存储的时候后并不是把该符号存储到内存中,而是将某些数据以二进制的形式放到内存中。这些数据就是ASCII码值。该表具体如下:
在这里插入图片描述
由图可知,不同的ASCII码对应不同的字符。

小结

C语言中,数据类型分为整型、实数型、字符型。整型又分为short, int ,long, long long, 实数型又分为float, double等,不同的类型其存储所占的字节数不同。
我们要谨慎使用强制类型转换,要注意精度丢失的问题,编程时要非常小心。

猜你喜欢

转载自blog.csdn.net/Birdyxh/article/details/112465373