数据的存储(1)

本章的重点

1.数据类型详细介绍

2.整形在内存中的存储:原码、反码、补码

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

4.浮点型在内存中的存储解析

1.数据类型介绍

前面我们已经学习了基本的内置类型(C语言本身就具有的类型):

char         //字符数据类型

short        //短整型

int            //整形

long         //长整型

long long //更长的整形(C99中才引入的)

float         //单精度浮点数

double     //双精度浮点数

//C语言有没有字符串类型

以及他们所存储空间的大小

sizeof(long)>=sizeof(int)

类型的意义:

  • 1.使用这个类型开辟内存空间的大小(大小决定了使用范围)
  • 2.如何看待内存空间的视角

1.1类型的基本归类:

整形家族

char             

        unsigned char

        signed char

//字符的本质是在内存中存储的是ASCII码值,是整形,所以划分到整形家族中

//char是unsigned char还是signed char标准是未定义的,这取决于编译器的实现

//多多数编译器都是signed char

short

        unsigned short [ int ]

        signed short [ int ]

int       

        unsigned int

        signed int

//平时写int a;实际这里int就是signed int

long

        unsigned long [ int ]

        signed long [ int ]

long long

        unsigned long long [ int ]

        signed long [ int ]

int a=10;

a是一个整型,有符号的整型,一个整型是4个字节==32bit

00000000 00000000 00000000 00000000

高位是符号位(第一位):符号位是0,表示正数;符号位是1,表示负数

浮点型家族:只要表示小数就可以使用浮点数

float

double

//float的精度低,存储的数值范围较小,double的精度高,存储的数据的范围更大

构造类型:自定义类型-我们可以自己创建出新的类型

数组类型

结构体类型 struct

枚举类型     enum

联合类型     union

指针类型:

int  *pi;

char  *pc;

float* pf;

void* pv;

空类型:

void表示空类型(无类型)

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

 明确了不需要传参数,但是还是传参数也能正常运行

2.整形在内存中的存储

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

那么数据在所开辟内存中是如何存储的?

比如:

int a=20;

int =-10;

2.1原码、反码、补码

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

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

1.正的整数,原码、反码、补码相同

2.负的整数,原码、反码、补码是需要计算的

原码:直接通过正负的形式写出的二进制序列就是原码

反码:原码的符号位不变,其他位按位取反得到的就是反码

补码:反码+1得到补码

补码到原码-->2种方式

1.-1\取反得到原码

2.补码取反\+1得到原码

数值有不同的表示形式:

2进制

8进制

10进制

16进制

比如,十进制的21用其他进制表示

二进制:0b10101

八进制:025

十进制:21

十六进制:0x15

内存本质上存的还是二进制,通过内存窗口观察不方便,所以用十六进制表示

 所以整形在内存中存放的是补码的二进制序列

存放补码的原因:

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

一个十六进制位等于四个二进制位,两个十六进制位就是八个二进制位(一个字节)

  • 内存中存放的是补码
  • 整形表达式计算使用的是内存中补码计算的
  • 打印和我们看到的都是原码

2.2大小端介绍

什么是大端、小端

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

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

 以字节为单位来讨论顺序的,两个十六进制为表示一个字节

大端字节序存储:

把数据的高位字节序的内容存放在低地址处,把低位字节序的内容放在高地址处,就是大端字节序存储

小端字节序存储:

把数据的高位字节序的内容存放在高地址处,把低位字节序的内容放在低地址处,就是小端字节序存储

如何判断当前编译器是大端还是小端?

我们常用的X86结构是小端模式

大小端是以字节位单位的​​​​​​​

大小端字节序指的是数据在电鸟上存储的字节顺序

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;

a是整数,要放到char类型中要发生截断,内存中是放补码的

-1

10000000 0000000 00000000 000000001--原码

111111111 11111111 111111111 1111111110--反码

111111111 11111111 111111111 1111111111--补码

111111111--截断

%d是打印的有符号的整形

所以char a要发生整型提升,char a是有符号的的char,a的最高位看成是符号位,整型提升是按符号位来提升,所以a在提升的过程中,高位补1

111111111 11111111 111111111 1111111111--整型提升之后,这个依然是内存中的补码,%d打印的是原码

10000000 0000000 00000000 000000001--原码

所以打印a是-1

signed char b=-1;

a和b是一样的,打印的也是-1;

unsigned char c=-1;

10000000 0000000 00000000 000000001--原码

111111111 11111111 111111111 1111111110--反码

111111111 11111111 111111111 1111111111--补码

111111111--截断

 %d打印整形,所以c要发生整型提升,因为c是unsigned char没有符号位,高位直接补0;

00000000 0000000 00000000 1111111111--补码

%d打印的是有符号数,因为这个补码的符号位是0,所以是正数,而整数的原、反、补相同

00000000 0000000 00000000 1111111111--原码

所以打印c是255

截断后,打印的时候需要整形提升,整型提升的时候需要看这个数类型是有符号数还是无符号数,无符号数整型提升高位补0,有符号数看是负数还是正数,负数高位补1,正数高位补0,并看打印的时候是以%u打印还是以%d的形式打印,如果是以%d的形式打印,还需将补码转换为原码,如果是以%u的形式进行打印,直接打印即可,不需要将补码转换为原码

2.

#include<stdio.h>
int main()
{
    char a=-128;
    printf("%u\n",a);
    return 0;
}

%u-->打印无符号整形,认为内存中存放的补码对应的是一个无符号数

%d-->打印有符号整形,认为内存种存放的补码对应的是一个有符号数

10000000 00000000 00000000 10000000--原码

11111111   11111111   11111111   01111111 --反码

11111111   11111111   11111111   1000000 --补码

10000000--截断

11111111   11111111   11111111 10000000--整形提升

先整型提升然后再看是以无符号数打印

要打印无符号数,对于无符号数没有符号位的概念,所以整型提升之后直接打印

这道题若是printf("%d\n",a);//打印有符号的整形

11111111   11111111   11111111 10000000--整形提升(补码)

//4,294,967,168

3.

#include<stdio.h>
int main()
{
    char a=128;
    printf("%u\n",a);
    return 0;
}

00000000 0000000 00000000 10000000--原码

10000000--截断

11111111 11111111 11111111 10000000-整形提升

//4294967168

4.

#include<stdio.h>
int main()
{
    int i=-20;
    unsigned int j=10;
    printf("%d\n",i+j);
    return 0;
//按照补码的形式进行运算,最后格式化成为有符号的整数
}

-20

10000000 00000000 00000000 00010100--原码

11111111 11111111 11111111 11101011--反码

11111111 11111111 11111111 11101100--补码

10

00000000 00000000 00000000 00001010

-20+10

01111111 11111111 11111111 11101100

00000000 00000000 00000000 00001010

11111111 11111111 11111111  11110110(补码)

10000000 00000000 00000000 00001001(反码)

10000000 00000000 00000000 00001010(原码)

//-10

5.

#include<stdio.h>
int main()
{

    unsigned int i;
    for(i=9;i>=0;i--)
    {
        printf("%u\n",i);
    }
}

后面开始死循环

i是无符号数,当i一直减小到我们认为的负数的时候,第一位不是符号位,由于是无符号数,会被当成无穷大的数

整形家族的类型的取值范围:limits.h

浮点型家族类型的取值范围:float.h

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值