C语言——数据在内存中的存储(上篇)

本次向大家详细介绍数据的类型,以及不同类型的数据在计算机中的存储方式。

主要内容如下

1. 数据类型介绍

2. 数据在内存中的存储:原码、反码、补码

3. 大小端字节序介绍及判断

4. 浮点型在内存中的存储方式

1.数据类型

char            //字符数据类型  字节大小为1个字节

short          //短整型              字节大小为2个字节

int               //整形                 字节大小为4个字节       

long            //长整型              字节大小为4/8个字节

long long   //更长的整形       字节大小为8个字节

float            //单精度浮点数   字节大小为4个字节

double        //双精度浮点数   字节大小为8个字节

类型的意义:                   

                        1. 使用这个类型开辟内存空间的大小(大小决定了使用范围)。

                        2. 如何看待内存空间的视角。

1.1、数据类型:

整形家族:

char                                     C99未定义char是有还是无符号字符型

         unsigned char           无无符号字符型

         signed  char              有符号字符型

short                                   短整形   或者 有符号短整型

         unsigned short         无符号短整形

         signed short              有符号短整型

int                                        整形 或者 有符号整形

         unsigned int              无符号整形

         signed int                  有符号整形

long                                    长整形  或者 有符号长整形

         unsigned long           无符号长整形

         signed long               有符号长整形

这里因为字符型数据在内存的存储为相应的ASCLL所以将其归类为整形家族

浮点型家族:

float                // 单精度浮点型

double            // 双精度浮点型

构造类型:

> 数组类型

> 结构体类型: struct

> 枚举类型   :  enum

> 联合类型   :  union

指针类型:

int *pi;                 整形指针

char *pc;             字符型指针

float* pf;              单精度浮点型指针

void* pv;              双精度浮点型指针

空类型:

void 表示空类型(无类型)

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

2. 整形在内存中的存储

一个变量的创建时需要要在内存中开辟空间。空间的大小是根据不同的类型而决定的。

例如:

int a = 10;

int b = -10;

 

 可以看到在创建变量a和变量b的时候内存分别开辟了4个字节的空间

(这里为16进制的数据,俩位16进制的数据在一起表示1个字节)

那么我们创建的数据又是如何在计算机中存放的呢?

2.1 原码、反码、补码

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

三种表示方法均有符号位数值位两部分,符号位都是用0表示,用1表示,而数值位

正数的原、反、补码都相同。

负整数的三种表示方法各不相同。

原码

直接将数值按照正负数的形式翻译成二进制就可以得到原码。

反码

将原码的符号位不变,其他位依次按位取反就可以得到反码。

补码

反码+1就得到补码。

对于整形来说:数据存放内存中其实存放的是补码。

原因如下:

在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统 一处理;

同时,加法和减法也可以统一处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程

是相同的,不需要额外的硬件电路。

例如在32位机器下

int  a = 1;

原码:0000 0000  0000 0000  0000 0000 0000 0001

反码:0000 0000  0000 0000  0000 0000 0000 0001

补码:0000 0000  0000 0000  0000 0000 0000 0001

int a = -1;

原码:1000 0000  0000 0000  0000 0000 0000 0001

反码:1111  1111  1111  1111   1111  1111  1111 1110

补码:1111  1111  1111  1111   1111  1111  1111 1111

通过调试我们可以找到a,b变量在内存中存储的空间

 

可以看出变量a和变量b在内存中存储的都是相应的二进制补码,但是他存储数据的位置却是反过来的,这是为什么呢?

当然在就引出我们后面的内存:

2.2 大小端介绍

什么是大端小端:

大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址 中;

小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,,保存在内存的高地 址中。

为什么有大端和小端:

这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为8 bit。但是在C语言中除了8 bitchar之外,还有16 bitshort 型,32 bitlong型(要看具体的编译器),另外,对于位数大于8位的处理器,例如16位或者32 位的处理器,由于寄存器宽度大于一个字节,那么必然存在着一个如何将多个字节安排的问题。因 此就导致了大端存储模式和小端存储模式。

 

例如:一个 16bit short x ,在内存中的地址为 0x0010 x 的值为 0x1122 ,那么 0x11 为 高字节, 0x22 为低字节。对于大端模式,就将 0x11 放在低地址中,即 0x0010 0x22 放在高 地址中,即 0x0011 中。小端模式,刚好相反。我们常用的 X86 结构是小端模式,而 KEIL C51 则 为大端模式。很多的ARMDSP都为小端模式。有些ARM处理器还可以由硬件来选择是大端模式 还是小端模式。

当然这里我们用一个形象一点的图片来告诉大家大小端的区别,

 当然在内存中数据如何放进去的我们就如何拿出来

当然我们也可以通过代码的形式获取内存中数据的存储方式

 

可以看出,这里的存储方式为小端字节序存储

当然我们也可以这样写

 

这样我们就可以写一个程序来判断

 

#include <stdio.h>

int check_sys()
{
     int i = 1;
     return (*(char *)&i);//取出i的地址强制将类型转换为char*类型,在解引用
}
int main()
{
     int ret = check_sys();
     if(ret == 1)
     {
         printf("小端存储\n");
     }
     else
     {
         printf("大端存储\n");
     }
     return 0; 
}

 2.3代码讲解

如果大家还是对数据的各种类型不是很了解,那么可以看看下面的代码讲解

1.

//输出什么?

#include <stdio.h>

int main()

{

   char a= -1;

   signed char b=-1;

   unsigned char c=-1;

   printf("a=%d,b=%d,c=%d",a,b,c);

   return 0;

}

可以看到我们的结果是这样样子的,我们为什么呢?

我们知道数据在内存中的存储是以补码的形式进行存储的

那么我们就可以得到他们相应的补码

char  a = -1

原码:1000 0000  0000 0000  0000 0000 0000 0001

反码:1111  1111  1111  1111   1111  1111  1111 1110

补码:1111  1111  1111  1111   1111  1111  1111 1111

sigend char  a = -1

原码:1000 0000  0000 0000  0000 0000 0000 0001

反码:1111  1111  1111  1111   1111  1111  1111 1110

补码:1111  1111  1111  1111   1111  1111  1111 1111

 

unsigend char  a = -1

原码:1000 0000  0000 0000  0000 0000 0000 0001

反码:1111  1111  1111  1111   1111  1111  1111 1110

补码:1111  1111  1111  1111   1111  1111  1111 1111

 

 这是这三种类型的数据在储存时候的情形

但是当他们要拿出来的时候

当将这些char类型数据以int类型进行打印的时候会发生整形提升

例如:

char a = -1;

原码: 1000 0001

反码: 1111 1110

补码: 1111 1111

 

 

sigend char a = -1;

原码: 1000 0001

反码: 1111 1110

补码: 1111 1111

 

 

unsigend char a = -1;

原码: 1000 0001

反码: 1111 1110

补码: 1111 1111

 

 可以看出和我们编译器算出的结果相同

2.

#include <stdio.h>

int main()

{

   char a = -128;

   printf("%u\n",a);

   return 0;

}

char a  = -128;

补码:1000  0000

当将这个数据转换为无符号的整形的时候

 

可以看出和我们编译器所算的结果相同 

3.

#include <stdio.h>

int main()

{

   char a = 128;

   printf("%u\n",a);

   return 0;

}

char a  = 128;

补码:1000  0000

这里我们可以看出 char类型下的 128 和 -128的补码相同,所以结果和上述结果相同

4.

int = -20;

unsigned  int  j = 10;

printf("%d\n", );

 

  • 16
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值