基本数据类型

  C语言的数据类型有很多种,分为整型、浮点型、字符型、构造类型等几个大类,每个类型都有着不同的容量,所占的内存也不同,甚至同一种数据类型在不同的系统下,也会有着不同的大小,所以在我们使用这些数据类型的时候,一定要注意这些。

char        //字符数据类型
short       //短整型
int         //整形
long        //长整型
long long   //更长的整形
float       //单精度浮点数
double      //双精度浮点数

 

  浮点型

float
double

  整型

char
 unsigned char
 signed char
short
 unsigned short [int]
 signed short [int]
int
 unsigned int
 signed int
long
 unsigned long [int]
 signed long [int]

  构造类型

> 数组类型
> 结构体类型 struct
> 枚举类型 enum
> 联合类型 union

  指针类型

void 表示空类型(无类型) 通常应用于函数的返回类型、函数的参数、指针类型

 

  而我们在C语言前期的学习中,最常见的数据类型就是,整形和浮点型了,所以下面分别介绍一下,他们是如何存储的。

大端字节序、小端字节序

    首先我们先来了解一下,在内存中,什么是大端字节序,什么是小端字节序;

    数据在内存中的存储形式都是以二进制数的方式所表示的,比如说我们要将int8这个十进制数存入内存,编译器会帮助我们将其转换为二进制形式

    0000 0000  0000 0000  0000 0000  0000 1000

    一共32位,这里我们先不探讨数据在内存中是怎么转换为二进制形式进行存储的。这32位二进制一共是4个字节,系统会以每个字节为一个单位连续在内存存储,因此为了方便起见,我们往往将内存中的数据以十六进制进行表示。

    因为1位十六进制数等于4位二进制数,也就是一个字节原本需要8位二进制表示,现在只需要用2位十六进制进行表示即可,通常我们在内存监视器中所看到的数据存储也大多是以十六进制进行表示的。

    将这么一串二进制转换为十六进制即可表示为00 00 00 08但是实际在内存中是以二进制进行存储的,在这里用十六进制是为了方便我们进行观察。

    之后就要将这么一串数据存入内存中了,但是问题来了,我们是要将最高位1个字节的数据首先存储在低地址区,还是要将最低位1个字节的数据首先存储在低地址区呢?

    其实这两种存储方式都是存在的,而具体的存储方式与我们电脑的CPU密切相关(其实也并不仅由CPU决定,具体来说是和环境也就是平台密切相关,但CPU占大头)。

    因此在当前的市场就有了大小端字节序之称,专门用来用来区分这两种不同的数据在内存中的存储方式。那么这两种存储方式具体有什么区别呢?

    1、大端字节序:低位存储在高地址上,依然以上方为例,那么在内存中以这样的方式进行存储:00 00 00 08

    2、小端字节序:低位存储在低地址上,依然以上方为例,那么在内存中以这样的方式进行存储:08 00 00 00

  注:①要是不好区分这两种存储方式,那么记住“小小小”——小(低位)小(低地址)小(小端)

    ②大小端字节序仅仅决定数据在内存中的存储,并不会因此改变数据本身的值!!!

    实例:写代码,求自己电脑的存储方式;

#include <stdio.h>
int main()
{
  int a = 0x11223344;
  char* p = (char*)&a;
  if(*p == 0x11)
  {
    printf("大端!\n");
  }
  else
  {
    printf("小端!\n");
  }
 return 0;
}

整型在内存中的存储

    说到这个就会牵扯到原码、反码、补码这三个知识点了;整型数据在计算机内存中都是以补码的形式进行存储的,而进行这样存储的时候,需要进行以下操作:

      数据->二进制(原码)->补码->反码

    有符号整形

      以整型数据-8为例,在有符号的情况下,系统会将第一位二进制位保留下来,作为符号位,0——正数,1——负数;这也解释了32位的整形,在有符号的情况下为什么最大只能存储21的亿数据;

      除过第一位,我们把其他位填补上数据的二进制位即可,那么-8的二进制就可表示为:10000000 00000000 00000000 00001000,这串二进制就叫做原码;

      之后我们对于原码进行操作,符号位保持不变,其他各位全部取反,表示为:11111111 11111111 11111111 11110111,这就是反码;

      最后对反码进行操作,我们只需在反码的基础上进行加1即可得到补码,表示为:11111111 11111111 11111111 11111000,这就是补码;

      上面进行的转换是针对负数在内存中的存储,而正数在内存中原码、发反码、补码都是一样的,与原码相同。

    无符号整型

      无符号整形与有符号整形基本类似,只是其省略了最高位的符号位而已,因此使得无符号的最大值比有符号整形最大值大了一倍,但也因此使得无符号整型无法表示负数。

    为什么要用到补码?

      因为硬件的制造比软件难,所以为了使硬件制造简单,那么在软件上就要加大难度,这样才能实现更多的性能;如果不使用补码,硬件上就要制造出加法器、减法器、乘法器等等;

      但是有了补码,那么我们可以将减法转化为加上一个负数,乘法转化为连续相加某个数,除法可以转化为连续减去某个数;这样一来,那么我们在硬件上只需提供一种加法器,就可以完成上面的操作,大大减少了硬件上的难度;

      另外,使得cpu可以将符号域与数值域共同参与运算,大大提高了运算效率,所以,补码是非常重要的。

浮点型在内存中的存储

    关于浮点型在内存中的存储十分复杂,在这里只作简单讲解。

    浮点型在内存中的存储与整形可以说是天差地别。根据国际标准IEEE的规定,任意一个二进制浮点数可以表示为以下的形式:

    (-1)^S * M * 2^E

    (-1)^s表示符号位,当s=0,V为正数;当s=1,V为负数。

    M表示有效数字,大于等于1,小于2。

    2^E表示指数位

    其中E和M的大小共同决定着这个数据的精度,而double之所以比float进度更高也是因为其在数据存储域的划分上有着更多的存储空间。

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

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

    3. IEEE 754对有效数字M和指数E,还有一些特别规定。 

 

    关于其中的细节,还有着十分严密甚至是严苛的规定和标准,具体请参考IEEE 754