C语言--数据的存储1

news/2024/10/24 2:29:39/

目录

  • 数据类型的介绍
    • 类型的意义
  • 类型的基本归类
    • 整形家族
    • 浮点型家族
    • 构造类型--自定义类型
    • 指针类型
    • 空类型
  • 整形在内存中的存储
  • 大小端
    • 大小端如何区分
    • 为什么会有大小端
    • 判断机器字节序

从本章开始,我们将正式进入C语言的进阶学习中。
本篇内容我们将学习 数据的存储

数据类型的介绍

在以往的学习当中,我们已经接触过许多的基本数据类型了,如下:

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

那么C语言中有没有字符串类型呢?
其实在C语言的环境中是没有的,很多高级语言java #c就有字符串类型,有string来表示字符串,用法和int很类似,但在C语言中字符串是通过字符指针来间接实现的。

类型的意义

我们使用这个类型可以开辟不同大小的空间(大小决定了使用范围)(例如int类型就会开辟4个字节大小的空间),同时也为程序员提供了一个观察内存空间的视角

类型的基本归类

整形家族

charunsigned charsigned char
shortunsigned short [int]signed short [int]
intunsigned intsigned int
longunsigned long [int]signed long [int]

我们发现,char类型也被归在了整形家族中,这是因为在存储字符的时候,实际上是储存的ascll码值,而ascll码值实际上也是一串数字,所以char类型实际上也隶属于整形家族。

浮点型家族

double
float

构造类型–自定义类型

//结构体类型
//数组类型
//枚举类型
//联合体

指针类型

int* pi;
char* pc;
float* pf;
double* pb;

空类型

void

void 表示空类型
空类型的作用在于:
1,可作为函数的返回类型: void test ()
2,可作为函数的参数: void test ();
3,指针: void* p;

整形在内存中的存储

我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。
那接下来我们谈谈数据在所开辟内存中到底是如何存储的
举个例子:

int main()
{int a = -10;return 0;
}

图1

我们知道数据在内存中以2进制的形式存储。
而对于整数来说:
整数二进制有三种表示形式:原码,反码,补码
而对于正整数来说:原码,反码,补码相同。
对于负整数来说:原码,反码,补码是需要计算的。

就以a=-10为例,
先写原码
-10为负数,符号位就应该为1(正数就为0,负数就为1),10用二进制表示为1010

//原码
100000000000000000000000000000001010

反码就是符号位不变,将原码按位取反

//反码
111111111111111111111111111111110101

补码就是反码+1

111111111111111111111111111111110110

那么我们在内存中储存的究竟是-10的原码还是反码,还是补码呢?我们用监视的方法来看一下,如图2
图2
我们把数据提出来:FFFFFFF6→转换为2进制就为111111111111111111111111111111110110(比如最后四位对应6,6转换为2进制就为0110).

所以,整数在内存中的储存是以补码的形式储存的

那么为什么是存的补码而不是其他形式呢?我们举个例子:
我们首先要知道,编译器里是没有减法计算的,所谓的减法实际上还是加法运算,比如:1-1其实是1+(-1)

假设储存的是原码1的原码:00000000000000000000000000000000001
-1的原码:100000000000000000000000000000000011+(-1)=10000000000000000000000000000000010这是-2的原码,与我们想得到的0不相符

所以原码储存是行不通的,我们再来试试补码

假设储存的是补码
1的补码:00000000000000000000000000000000001-1的补码:111111111111111111111111111111111111+(-1)=:100000000000000000000000000000000000//多出的一位1丢掉变为00000000000000000000000000000000000这就是0的补码

所以只有用补码来计算才是正确的。
除此之外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

到这里我们发现有一个问题没有被解决,那就是监视器中显示的明明是F6 FF FF FF,但我们在读的时候却是反着读的,这里就要涉及新的概念:大端和小端

大小端

我们来看一个地址的存放,如图3
图3
图中第一和第二种就是大端字节序和小端字节序,第三种和第四种方法虽然在理论上来讲也是可行的,但是存放的过程就会变得过于复杂,所以不采用。

大小端如何区分

图4

如图4,我们假设地址11 22 33 44为一个数字,那么越靠近右边,代表着位数越低,而越靠近左边,代表着位数越高,所以右边为低位字节,左边为高位字节
根据我们定义的左边为低地址,右边为高地址,
大端(存储)模式定义为:数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中
小端(存储)模式定义为:数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中

速记的口诀是:小同大异
那么通过我们所学的知识,上述图片中的F6 FF FF FF就为小端存储模式

为什么会有大小端

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

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

判断机器字节序

我们通过设计一个小程序来判断当前机器的字节序
假设我们要存放的地址为 00 00 00 01

int main()
{int a = 1;char* p = (char*)&a;if (*p == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}

因为我们只想访问一个字节来判断是否为1,所以我们需要将&a强制转换为char类型,这样char就指向整形a的四个字节中的首个字节*。

我们同样可以通过函数的方法实现:

int check_sys()
{int a = 1;char* p = (char*)&a;if (*p == 1){return 1;}else{return 0;}
}
int main()
{int ret = check_sys();if (ret == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}

优化一下

int check_sys()
{int a = 1;char* p = (char*)&a;return *p;
}
int main()
{int ret = check_sys();if (ret == 1){printf("小端\n");}else{printf("大端\n");}return 0;
}

三种方法运行结果如图4
图4
所以我的电脑采用的是小端存储模式

以上就是本章的全部内容了,如有出入,欢迎指正。


http://www.ppmy.cn/news/153367.html

相关文章

数据存储格式

文章目录 数据存储格式1 行列存储比较2 ORC文件格式2.1 文件级2.1.1 Post scripts2.1.2 File Footer2.1.3 File MetaData 2.2 Stripe级2.2.1 Stripe Footer2.2.2 Row Data2.2.3 Index Data 3 Parquet文件格式3.1 Header3.2 Data3.2.1 Row Group3.2.2 Column Chunk3.2.3 Page 3.…

【线性dp必学四道题】线性dp四道经典例题【最长上升子序列】、【最长公共子序列】、【最长公共上升子序列(maxv的由来)】【最长公共子串】

【最长上升子序列】、【最长公共子序列】、【最长公共上升子序列】 最长上升子序列f[i] 表示以i结尾的最长子序列 最长公共子序列f[i][j] 表示 a前i 和 b前j个 最长公共长度 最长公共上升子序列f[i][j]代表所有a[1 ~ i]和b[1 ~ j]中以b[j]结尾的公共上升子序列的集合 最长公共子…

硬件入门设计

硬件入门设计 常见器件的选型 电阻器器件选型 电阻选型需要注意的参数:阻值、封装、功耗、精度。 电阻选型技巧: 确定电阻安装方式确定电阻阻值。:根据电路计算取值、根据电阻数据手册取值、根据积累经验取值。选择封装和功耗选择电阻精度…

硬件设计-DIY项目分享

今天逛Hackday看到一个有趣的项目,一个外国老兄电脑是双系统,每次切换到win,都需要在系统启动界面手动输入指令,很麻烦。 为了偷懒他设计了一个物理层面的系统切换装置,如下图。 他的主要思路是, 1. 用ST…

主机DIY玩家的必备工具包

前段时间在装机的时候,用到了一款图拉丁吧网友自制的工具包-图吧工具箱,觉得十分不错,这不刚好又赶上年终1212购物节,分享出来,给准备DIY主机的朋友一些参考。 图吧工具箱 图吧工具箱号称是最纯净的硬件工具箱&#…

DDR4原理及硬件设计

DDR4的工作原理以及寻址方式 DDR4是什么? DDR4全称,DDR4-DRAM,与其他DDRDRAM一样,是当前电子系统架构中使用最为广泛的的RAM存储器。 这句话可以分解出3个关键字:存储器、DRAM、DDR4。 先说存储器, 说到…

电脑新手也能学会的diy装机教程

对于刚刚开始接触diy装机的网友来说,组装电脑并不是一件简单的事情,因此很多网友都想了解要怎么组装电脑。其实组装台式电脑的步骤并不难,掌握一定的操作即可,下面小编就给大家分享一个电脑新手也能学会的diy装机教程。 具体的安…

精选汇总 | 硬件DIY

关注星标公众号,不错过精彩内容 作者 | strongerHuang 微信公众号 | 嵌入式专栏 为了方便大家平时公交、地铁、外出办事也能用手机回顾查看文章,我特意用心精选,并分类整理了部分文章: DIY | 用铁丝做Arduino UNO板(附…