(深度剖析数据在内存中的存储) C语言从入门到入土(进阶篇)(一)

简介: 1. 数据类型介绍 1.1 类型的基本归类 2. 整形在内存中的存储 2.1 原码、反码、补码 这里同时补充一下源码求补码的两种方法: 2.2 大小端介绍 2.3 练习 (每题都能让你意想不到) 3. 浮点型在内存中的存储 3.1 一个例子 3.2 浮点数存储规则 3.3对浮点数存储的补充

1. 数据类型介绍

前面我们已经学习了基本的内置类型:


char         // 字符数据类型

short       // 短整型

int         // 整形

long         // 长整型

long long   // 更长的整形

float       // 单精度浮点数

double       // 双精度浮点数

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


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

C99之前没有 longlong

int 在16位操作系统下 占2字节  32位 4字节  64位 4字节 (VS)

在新的标准下还有long double这样的类型

19.png



布尔类型 _Bool  是用来表示真假的,早期人们是用 1  0  来表示真假 现在:


20.png

定义了ture(1) 和 false(0)   其实本质上_Bool 本质上就是 int 的重命名


当然用时要有头文件


我们一般说的int long 都是 unsigned int(long),short也是。但是对于char


是没有规定是 signed char 还是 unsigned char ,但是常见的编译器里面我们用


的时候他是signed char。


类型的意义:


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

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


1.1 类型的基本归类


整形家族:


char

unsigned char

signed char

short

unsigned short [ int ]

signed short [ int ]

int

unsigned int

signed int

long

unsigned long [ int ]

signed long [ int ]


当我们打印有符号时应该用%d打印,用无符号时应该用%u


21.png

这里虽然是-10,但是我们是用%d来解析,就是有符号

这里我们改为%u:

22.png


大家看下图就很好理解了23.png

也就是说一开始的数字先放入先前开辟的空间当中同时转化为二进制数,然后再存储到内存中时才会看类型来看是有符号还是无符号,有符号就看符号位,无符号就直接把存进去的补码当成源码。


浮点数家族:

float

double


构造类型:

> 数组类型

> 结构体类型 struct

> 枚举类型 enum

> 联合类型 union


构造类型也叫自定义类型,比如int arr【10】  和 int arr【5】 就是两种类型,我们把函数名这里是arr除去,留下的就是类型名,这里是int 【10】 和 int 【5】 ,所以是自定义类型。


指针类型

int *pi;

char *pc;

float* pf;

void* pv;


24.png


空类型:


void 表示空类型(无类型)

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


2. 整形在内存中的存储


我们之前讲过一个变量的创建是要在内存中开辟空间的。空间的大小是根据不同的类型而决定的。

那接下来我们谈谈数据在所开辟内存中到底是如何存储的?


比如:

int a = 20 ;

int b = - 10 ;


我们知道为 a 分配四个字节的空间。

那如何存储?

下来了解下面的概念:


2.1 原码、反码、补码

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

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


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

原码

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

反码

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

补码

反码 +1 就得到补码。

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

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


为什么呢?

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

同时,加法和减法也可以统一处理( CPU 只有加法器 )此外,补码与原码相互转换,其运算过程 是相同的,不需要额外的硬件电路。


 我们看看在内存中的存储:

25.png

26.png

27.png


整数在内存中存的是补码,这是为什么呢?

这是因为:


29.png


这里同时补充一下源码求补码的两种方法:


法一:就是我们通识的源码得到反码就是符号位不变其他位按位取反然后反码得到补码就是反码加一。由补码得到源码就是逆着回去。


法二:这是作者比较喜欢用的。其实我们由补码得到源码一样可以按源码得到补码的方法,也就是说可以补码符号位不变,其他位按位取反得到反码,然后反码加一得到源码。这很神奇,大家可以自行验证哈!


然后接着正文:


我们可以看到对于a和b分别存储的是补码。但是我们发现顺序有点不对劲。


这是又为什么?


2.2 大小端介绍

什么是大端小端:

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

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


为什么有大端和小端:


为什么会有大小端模式之分呢?这是因为在计算机系统中,我们是以字节为单位的,每个地址单元 都对应着一个字节,一个字节为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 处理器还可以 由硬件来选择是大端模式还是小端 模式。


百度2015年系统工程师笔试题:

请简述大端字节序和小端字节序的概念,设计一个小程序来判断当前机器的字节序。

#include <stdio.h>
int check_sys()
{
 int i = 1;
 return (*(char *)&i);
}
int main()
{
 int ret = check_sys();
 if(ret == 1)
 {
 printf("小端\n");
 }
 else
 {
 printf("大端\n");
 }
 return 0; }
相关文章
|
2月前
|
存储
阿里云轻量应用服务器收费标准价格表:200Mbps带宽、CPU内存及存储配置详解
阿里云香港轻量应用服务器,200Mbps带宽,免备案,支持多IP及国际线路,月租25元起,年付享8.5折优惠,适用于网站、应用等多种场景。
724 0
|
2月前
|
安全 C语言 C++
比较C++的内存分配与管理方式new/delete与C语言中的malloc/realloc/calloc/free。
在实用性方面,C++的内存管理方式提供了面向对象的特性,它是处理构造和析构、需要类型安全和异常处理的首选方案。而C语言的内存管理函数适用于简单的内存分配,例如分配原始内存块或复杂性较低的数据结构,没有构造和析构的要求。当从C迁移到C++,或在C++中使用C代码时,了解两种内存管理方式的差异非常重要。
124 26
|
2月前
|
安全 C语言
C语言中的字符、字符串及内存操作函数详细讲解
通过这些函数的正确使用,可以有效管理字符串和内存操作,它们是C语言编程中不可或缺的工具。
238 15
|
2月前
|
存储 缓存 NoSQL
内存管理基础:数据结构的存储方式
数据结构在内存中的存储方式主要包括连续存储、链式存储、索引存储和散列存储。连续存储如数组,数据元素按顺序连续存放,访问速度快但扩展性差;链式存储如链表,通过指针连接分散的节点,便于插入删除但访问效率低;索引存储通过索引表提高查找效率,常用于数据库系统;散列存储如哈希表,通过哈希函数实现快速存取,但需处理冲突。不同场景下应根据访问模式、数据规模和操作频率选择合适的存储结构,甚至结合多种方式以达到最优性能。掌握这些存储机制是构建高效程序和理解高级数据结构的基础。
209 0
|
2月前
|
存储 弹性计算 固态存储
阿里云服务器配置费用整理,支持一万人CPU内存、公网带宽和存储IO性能全解析
要支撑1万人在线流量,需选择阿里云企业级ECS服务器,如通用型g系列、高主频型hf系列或通用算力型u1实例,配置如16核64G及以上,搭配高带宽与SSD/ESSD云盘,费用约数千元每月。
199 0
|
9月前
|
存储 程序员 编译器
C 语言中的数据类型转换:连接不同数据世界的桥梁
C语言中的数据类型转换是程序设计中不可或缺的一部分,它如同连接不同数据世界的桥梁,使得不同类型的变量之间能够互相传递和转换,确保了程序的灵活性与兼容性。通过强制类型转换或自动类型转换,C语言允许开发者在保证数据完整性的前提下,实现复杂的数据处理逻辑。
|
9月前
|
存储 编译器 程序员
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
在C语言中,内存布局是程序运行时非常重要的概念。内存布局直接影响程序的性能、稳定性和安全性。理解C程序的内存布局,有助于编写更高效和可靠的代码。本文将详细介绍C程序的内存布局,包括代码段、数据段、堆、栈等部分,并提供相关的示例和应用。
305 5
【C语言】内存布局大揭秘 ! -《堆、栈和你从未听说过的内存角落》
|
9月前
|
存储 缓存 算法
【C语言】内存管理函数详细讲解
在C语言编程中,内存管理是至关重要的。动态内存分配函数允许程序在运行时请求和释放内存,这对于处理不确定大小的数据结构至关重要。以下是C语言内存管理函数的详细讲解,包括每个函数的功能、标准格式、示例代码、代码解释及其输出。
328 6
|
存储 编译器 C语言
【C语言篇】数据在内存中的存储(超详细)
浮点数就采⽤下⾯的规则表⽰,即指数E的真实值加上127(或1023),再将有效数字M去掉整数部分的1。
813 0