【C语言进阶】深度刨析数据在内存中的存储(上)

目录

一、数据类型介绍 

  二、整形在内存中的存储 

补充:

 三、大小端字节序


一、数据类型介绍 

C语言基本的内置类型:

char            //字符数据类型

short          //短整型

int              //整型

long           //长整型

long long   // 更长整型

float          //单精度浮点数

doublt       //双进度浮点数

1、 类型归类:

1>、整型家族:

char (字符在内存中是以ASCII值的形式存储,ASCII是整数,所以char可以归类到整型家族中)

       unsigned  char (无符号字符)

        signed  char (有符号字符)

short

        unsigned short [int]   

        signed short [int]   在C语言中规定(short = singed char),int  long 同理

int

        unsigned int 

        signed int 

long

        unsigned long [int]

        signed long [int]

 注释:char和 short、int、long 不同 ,c语言语法没有明确规定,若需要有符号char,用signed char ;需要无符号char,用unsigned char。

 2>、浮点型家族:

float  (单精度浮点数)

doublt  (双精度浮点数)

3>、构造类型:(自定义类型)

1>、数组类型

2>、结构体类型 struct

3>、枚举类型 enum

4>、联合类型 union

4>、 指针类型

int *pi;

char *pc;

float *pf;

void *pv;

5>、空类型:

void 表示空类型(无类型)

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


  二、整形在内存中的存储 

1、原码、反码、补码

在计算机系统中,数据一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理;同时、加法和减法也可以统一处理(cpu只有加法器)此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

原码、反码、补码相关知识点,从下面链接查看

   http://t.csdn.cn/Bd2Hl


补充:

1、数据类型与原码、反码、补码练习

#include<stdio.h>
int main()
{
    char a = -1;
    //在内存中存储的是补码
    //10000000000000000000000000000001  —— -1的原码
    //11111111111111111111111111111110  —— -1的反码
    //11111111111111111111111111111111  —— -1的补码
    //11111111 -a ,发生截断
    signed char b = -1;
    unsigned char c = -1;
    //11111111111111111111111111111111  —— -1的补码
    //11111111 -c ,当在unsigned char 的环境下-1发生截断后,第一位代表的就不是符号位,他也 
    //就是数值位
    printf("a = %d,b = %d, c = %d",a,b,c);//以%d形式打印,打印的是整型,补码是32位bit 
    //位,所以在打印的时候要进行整型提升.
    //a 整型提升  
    //11111111  有符号数整型提升的时候按符号位提升(高位补符号位)。 
    //10000000000000000000000000000001  ——提升后的原码,整型提升后是-1
    //c 整型提升
    //11111111  无符号数整型提升的时候高位直接补0
    //00000000000000000000000011111111
    return 0;
}
结果是:-1  -1  255

注释:以signed char 和unsigned char 为例:

整形提升的时候 :有符号数整型提升的时候按位提升(高位补符号位)。

                              无符号数整型提升的时候高位直接补0。

 2、有符号数和无符号数的取值范围如何确定

以signed char与unsigned char 在内存中的存储(以补码的形式存储)为例

 同理:signed short 的取值范围是 -32768~32767;unsigned short 的取值范围是0~65535。

          int 、long、等等都可以用这个思想来确定。

 练习:

1、

#include<stdio.h>
int main()
{
    char a = -128;
    //10000000000000000000000010000000 —— -128的原码
    //11111111111111111111111101111111 —— -128的反码
    //11111111111111111111111110000000 —— -128的补码
    //10000000 —— -存入a中,发生截断
    //%u  打印无符号整型,认为内存中存放的补码对应的是一个无符号数
    //%d  打印有符号整型,认为内存中存放的补码对应的是一个无符号数
    printf("%u\n",a);//整型提升 ,提升a就看a在当前编译器中为有符号char,按符号位提升。
    //11111111111111111111111110000000 —— -提升后的补码
    //因为提升后为无符号整型,则补码、原码相同,并且首位算入数值位。
    return 0;
}
结果是:4294967168

注释:如上述代码,打印时发生整形提升

1、首先看要提升的数在当前代码中是否为有符号类型的数(如:signed char),若是,          则按符号位提升,若是无符号类型的数(如:unsigned char),高位直接补0。

2、提升完成后,再看要求提升的是有符号还是无符号的数.在做相应的补码与原码的转换。

 2、

#include<stdio.h>
#include<windons.h>
int main()
{
    unsigned int i;
    for(i = 9;i >= 0;i--)
    {
        printf("%u\n",i);
        Sleep(100);//睡眠函数,防止打印过程太快
    }
}
结果是:0~9~死循环

 因为是无符号整型,当i=0之后,代码不会停止,通过i--,得到unsigned int 类型的取值范围中的最大值。

3、

#include<stdio.h>
int main()
{
    char a[1000];
    int i;
    for(i = 0;i < 1000;i++)
    {
        a[i] = -1 -i;
    }
    printf("%d",strlen(a));//strlen是以字符\0为结束标志,\0的ASCII码值是0,所以找到数组中 
    //0以前的字符,出现多少字符就是多少长度。
    return 0;
}
结果是:255

 char类型的取值范围是-128~127,127+128=255之后是0,0之前有255个字符,所以函数strlen得到的长度为255.


 三、大小端字节序

 如上述图片 代码中输入的16进制数的顺序与内存中的存储顺序是相反的。在这里就要提到大小端字节序的知识点。

1、概念

字节序,就是大于一个字节类型的数据在内存中的存放顺序

2、大小端介绍(以字节为单位来进行研究)

字节序经常被分为两类:

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

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

3、理解(高低地址和高低字节)

1>、高低字节

以0x11223344,这个16进制数字为例:

在十进制中靠近左边是高位,靠近右边是低位,在其他进制中也是一样。

0x11223344,从高位到低位的字节依次是 0x11,0x22,0x33,0x44.

2>、高低地址 

 在栈区:(从高内存地址,到低内存地址。即从栈底(高地址),到栈顶(低地址))。

上述例子,小端存储  0x44是低字节,其所在位置是地址的首位,是内存的低地址 。

 练习:请设计一个小程序来判断当前机器的字节序

#include<stdio.h>
int main()
{
    int a = 1;
    char *p = (char*)&a;//强制类型转换为char*类型,通过char*类型的指针查找int类型在内存中 
                        //的第一个字节的内容来判断大小端。
    if(1 == *p)
    printf("小端\n");
    else
    printf("大端\n");
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值