c语言——数据的存储

本文详细介绍了C语言中的数据类型分类,包括整型、浮点型、构造类型和指针类型,以及整型和浮点数在内存中的存储原理,如原码、反码、补码和大小端的概念。同时讨论了浮点数的存储规则和读取方式,遵循IEEE754标准。
摘要由CSDN通过智能技术生成

一、数据类型

       什么是数据类型:C语言中,为了方便编译器或者解释器程序员如何使用数据,根据数据的需要的空间大小对所有数据进行了分类。

二、类型的基本归类

在学习C语言初期,我们就会接触到如下基本的数据类型,了解了它们的用法和空间大小

char       //字符型数据类型(1bit)
short      //短整型(2bit)
int        //整型(4bit)
long       //长整型(4bit)
long long  //长长整型(8bit)
float      //单精度浮点型(4bit)
double     //双精度浮点型(4bit)

这里我们详细的介绍C语言各数据类型

1. 整型

char               //char有无符号是不确定的,需要具体根据编译器来看
  unsigned char    //无符号的字符型
  signed char      //有符号的字符型,一般默认有符号。
short
  unsigned short [int]//int可以省略。
  signed short [int]
int 
  unsigned int
  signed int
long
  unsigned long
  signed long

2. 浮点型

float 
double 
long double

3. 构造类型(自定义类型)

数组类型根据需要的数据类型选择相应的关键词
结构体类型struct
枚举类型enum
联合类型union

4. 指针类型

int* pi; 
char* pc; 
float* pf 
void* pv

5. 空类型

    void 表示空类型(无类型) 

    通常应用于函数的返回类型,函数的参数,指针类型。

三、整型在内存中的存储

1. 原码、反码、补码

      计算机中的整数有三种二进制表示方法,即原码反码补码。

      三种表示方法俊有符号位数值位两部分组成,符号位是指整型数组转化为二进制后,左边第一位数字,其中“0”表示“正”,“1”表示“负”。而数值位,根据整型数据正负不同,三种表示方法也有差异。

  • 正整数的原码、反码、补码是相同的,即直接换算为二进制后的数据;
  • 负整数的原码是之间按照正负数的形式翻译成二进制数据;
  • 负整数反码是在原码的基础上,除了符号位,其他位数按位取反;
  • 负整数的补码是在原码的基础之上加1即可;

比如:

int a = 5;//(32bit)转换位二进制是:101
//00000000000000000000000000000101(原码)
//00000000000000000000000000000101(反码)
//00000000000000000000000000000101(补码)
//第一个“0”表示正负符号位
//0为正、1为负
int b = -5;
//10000000000000000000000000000101(原码)
//11111111111111111111111111111010(反码)
//11111111111111111111111111111011(补码)
//负数的原码的符号位不变,其他位按位取反得到对应的反码。
//反码+1就是补码。

对于整数来说,内存中存放的是数据的补码,打印出来的是原码的值。原因是因为CPU中只有加法,要实现减法需要加符号如:1+(-1)。使用补码,可以将符号位和数值域统一处理。同时加法和减法也可以统一处理,此外,原码和补码相互转换,其运行过程是相同的,不需要额外的硬件电路。

2. 大小端介绍

2.1  什么是大小端

大小端字节序存储包括(概念):

      大端字节序存储:把一个数据低位字节处数据存放在高地址处,把高位字节处的数据存放在低地址处。如:

低< 11 22 33 44 >高

      小端字节序存储:把一个数据高位字节处数据存放在高地址处,把低位字节处的数据存放在低地址处。如:

低< 44 33 22 11 >高

2.2  为什么会有大小端

      在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节8个bit,对于位数大与8位的处理器,由于寄存宽度大于一个字节,那么必然存在着如何将多个字节安排的问题,因此导致了大端和小端存储模式。

我们可以通过一段代码来判断数据存储是大端还是小端

//通过判断该数据地址的第一个字节来确定大小端存储。
int check_sys()
{
    int a = 1;
    return *(char*)&a;
}

int check_sys(char* p)
{
    int a = 1;
    
}
int main()
{
    int a = 1;
    char* pa = &a;//int ret = check_sys();
    if(*p == 1)
    {
        printf("小端\n");    
    }
    else
    {
        printf("大端\n");    
    }
    //00000000000000000000000000000001
    //00 00 00 01,或01 00 00 00
    return 0;
}

四、浮点数在内存中的存储

1. 常见的浮点数

  • 3.141
  • 1E10

浮点数家族包括:float;double;long double等。

2. 浮点数存储规则

根据国际标准IEEE(电气和电子工程协会)754,任意一个二进制浮点数V可以表示成以下形式:

(-1)^S*M*2^E
//(-1)^S表示符号位,当S=0,V为正数,当S=1,V为负数。
//M表示有效数字,大于等于1,小于2。
//2^E表示指数位。

举例来说:

    十进制的5.0,写成二进制形式是101.0,相当于1.01×2^2。那么,按照以上规则,可以得到

S=0,M=1.01,E=2。((-1)^0*1.01×2^2)

     十进制的-5.0,写成二进制是-101.0,相当于-1.01×2^2。那么

S=1,M=1.01,E=2。

     浮点数存在有精度误差,原因是二进制保存浮点数时,对小数点表示可能存在总差一点的情况,导致二进制长度很长,因此要表示一些浮点数,只能通过四舍五入来表示。

IEEE规定:对于32位的浮点数,最高位的1表示符号位S,接着的8位是指数E,剩下的23位为有效数字M。

对于64位的浮点数,最高位的1表示符号位S,接着的11位是指数E,剩下的52位为有效数字M。

IEEE 754规定:有效数字M,M的取值为[1,2),也就是说,m可以写成1.xxxxx。同时,计算机在内部保存时,默认m的值最开头总为‘1’,因此1可以被舍去,只保存后面的小数部分。读取时再加上去,以增大浮点数的取值范围。

对于指数E,E是一个无符号数,这意味着如果E为8位,其取值范围为0~255,E为11位时,其取值范围为0~2047。但系统中的存储位置默认开头第一位是符号位,即默认数值有负数,与E本身发生冲突,因此在存储时,会在E原来的值上再添加一个数,对于8位的E,会在原来基础上加127;

对于11位的E,会在原来基础上加1023。如下:

int main()
{
    float f = 5.5;
    //二进制形式为101.1
    //根据浮点数存储规则表示为(-1)^0*1.001*2^2
    //S = 0
    //E = 2 + 127 = 129
    //M = 1.011
    //存储到内存中为:010000001011000000000000000000000
    return 0;
}

3. 浮点数的读取

浮点数的读取是按存储的规则逆序拿出。

分为以下三种情况:

  • E不全为0或不全为1:这时浮点数指数E的计算值减去127(或1023),得到真实值,再将有效数字M前加上第一位“1”。
  • E全0时:这时浮点数的指数E等于1-127(或1-1023)即为真实值。有效数字M不再加上第一位数字“1”,而是还原为0.xxxxxx的小数,这样做是为了表示+-0,以及接近于0的很小的数字。
  • E全为1时:这时,如果有效数字M全为0时,表示±无穷大的数字。(正负取决于S的符号位)

以上就是C语言中数据的存储的相关知识啦,如果有什么疑问或者哪里有错误,可以在评论区提出来,我是半路出家的C语言小白,请大家多多指教。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值