数据在内存中的存储(1)——整形

简介: 数据在内存中的存储(1)——整形

1、数据类型介绍


我们先来简单了解一下我们前面所学的基本的内置类型


数据类型 数据名 占内存字节数 表示范围
char 字符数据类型 1 -128~127
short 短整型 2 -32,768~32,767
int 整形 4 -2,147,483,648~2,147,483,647(-231 ~ 231-1)
long 长整型 4或者8 -2,147,483,648~2,147,483,647(-231 ~ 231-1)
long long 更长的整形 8 -9223372036854775808~9223372036854775807
float 单精度浮点数 4 -3.4x10-38 ~ 3.4x1038
double 双精度浮点数 8 -1.7x10-308 ~ 1.7x10308

这么多类型存在的意义在于使用者可以选择自己所需要合适的类型

 

       1.1、类型的基本归类


根据这些数据类型,我们给他们做一个简单的分类


               整形家族


char

unsigned  char

signed  char

short

unsigned  short

signed  short

int

unsigned  int

signed  int

long

unsigned  long

signed  int

这里char为什么放在整形家族里呢?是因为字符在存储的时候,存储的是ASCII码值,是整型,所以放在整型家族里,蓝色为无符号,紫色为有符号后续会讲到,这儿保留悬念

               浮点数家族


                                           float
                                           double

               指针类型


  关于指针有疑问的小伙伴可以去看看博主对指针的讲解

char*  pc
int*   pi
float*  float
void*  pv

                 空类型


void表示空类型(无类型)
通常用于函数的参数、函数的返回类型、指针类型

               构造类型


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


2、整形在内存中的存储


一个变量的创建是需要在内存中开辟空间的,而空间的大小是根据不同的类型来决定的。数据在这些空间中以二进制补码的形式存储,而计算机中有符号数有原码,反码,补码三种表示形式,并且还有符号位和数值位,符号位用0表示正数,1表示负数


        2.1、原码、反码、补码


我们这里用的是整型,而一个整形有4个字节=32bit位,所以二进制表示应为32位,第一位为符号位,1表示负数,0表示正数,中间用0补齐就好,正整数的原码、反码、补码表示如下

1. int a = 15;
2. //00000000000000000000000000001111 - 原码
3. //00000000000000000000000000001111 - 反码
4. //00000000000000000000000000001111 - 补码

负整数的原码、反码、补码是需要计算的,计算方法和原码、反码、补码表示如下

1. int b = -15;
2. //10000000000000000000000000001111 - 原码
3. //11111111111111111111111111110000 - 反码(原码的符号位不变,其他位按位取反得到的就是反码)
4. //11111111111111111111111111110001 - 补码(反码+1就是补码)

 我们还需要明确的是整数在内存中存储的是补码,计算的时候也是使用补码计算的


        2.2、大小端介绍


在介绍大小端是我们先来看几组现象,有助于我们理解,博主这里使用的编译器为vs2019


但我们查看num的地址我们发现,数据在上面倒着存储,这是正数,我们再来看一下负数

我们发现还是倒着存储的,这是为什么呢?

这是因为大端和小端这两种存储模式

     大端:是数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。低地址-->>高数据   例如:手机

     小端:是指数据的地位保存在内存的低地址中,数据的高位则保存在内存的高地址中。低地址-->>低数据    例如:电脑


这里呢我们想一下,除了通过调试,我们还有没有其他办法来判断大小端呢?

 

这里我们发现,当a=1时,大小端低位存储的值并不相同,所以我们写出以下代码

1. //int main()
2. //{
3. // int a = 1;
4. // char* p = (char*)&a;
5. // if (*p == 1)
6. //   printf("小端\n");
7. // else
8. //   printf("大端\n");
9. // return 0;
10. //}

那么这个代码又是如实现的呢? 这里我们需要明确一个知识点,其实这个博主在指针是也有所讲到,这里就在浅提一下吧

那么也就是所如果是访问的第一个字节是1那么就是小端,如果不是就是大端,如此一来就可以判断了

为什么会有大小端模式之分呢?

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

大小端存在的意义

1)在通信协议中,大小端模式是非常重要的。

2)在实际中,有些CPU用的是大端,有些则是小端,如不加以区别的话,可能会出现读取时和储存时字节顺序不一致的情况,从而造成数据的错误。

3)网络通信中一般为大端模式,常用计算机CPU为小端模式。


        2.3、有符号与无符号


    这里注意有符号和无符号只针对整形

在博主vs编译器上类型前面没有加unsigned都默认为有符号

我们知道数据在存储时是以二进制存储的,而二进制位的第一位为符号位,我们来看一个简单的演示再理解一下有符号和无符号

那么有符号与无符号对于我们的表示范围有没有区别呢?答案是显然的,有区别的

比如我们先来看一下有符号的吧

再来看一下无符号的,没有符号位,全是数值位

这里呢我们再拓展一下,当二进制位不断加一时,我们会发现到了极限时,又会回到最初位,这里我们借用大牛的图来理解一下

有符号的

无符号的

        2.4、练习


例一


下面是代码解释和最终结果

1. //#include <stdio.h>
2. //int main()
3. //{
4. // char a = -1;
5. // //10000000000000000000000000000001  原码
6. // //11111111111111111111111111111110  反码
7. // //11111111111111111111111111111111-截断,因为char只占一个字节
8. // //11111111 -a
9. // //11111111111111111111111111111111  整形提升
10. //  //11111111111111111111111111111110  反码
11. //  //10000000000000000000000000000001--> -1
12. //
13. //  signed char b = -1;
14. //  //11111111111111111111111111111111  反码
15. //  //11111111 -b
16. //  //11111111111111111111111111111111  整形提升
17. //  //11111111111111111111111111111110  反码
18. //  //10000000000000000000000000000001--> -1
19. //  unsigned char c = -1;
20. //  //11111111 -c   //无符号,前面补0
21. //  //00000000000000000000000011111111--.255
22. //  //
23. //  printf("a=%d,b=%d,c=%d", a, b, c);
24. //  //%d - 十进制的形式打印有符号整型整数
25. //  //整型提升
26. //
27. //  return 0;
28. //}

关于整形提升不懂的宝子,可以看博主在操作符(2)里的讲解


例二


代码解释与运行结果如下

1. //#include <stdio.h>
2. //int main()
3. //{
4. // char a = -128;
5. // //-128
6. // //10000000000000000000000010000000
7. // //11111111111111111111111101111111
8. // //11111111111111111111111110000000
9. // //-128的补码
10. //  //10000000 有符号,补首位
11. //  //11111111111111111111111110000000
12. //  //由于我们打印的是无符号,所以上面就为我们要的原码
13. //  printf("%u\n", a);
14. //  %u打印无符号的十进制数
15. //  return 0;
16. //}

例三


解释如下

1. //int main()
2. //{
3. // int i = -20;
4. // //10000000000000000000000000010100
5. // //11111111111111111111111111101011
6. // //11111111111111111111111111101100
7. // //
8. // unsigned int j = 10;
9. // //00000000000000000000000000001010 -->10
10. //  //11111111111111111111111111101100 -->-20
11. //  //11111111111111111111111111110110
12. //  //11111111111111111111111111110101
13. //  //10000000000000000000000000001010 -10
14. //  //
15. //  //11111111111111111111111111110110
16. //  //10000000000000000000000000001001
17. //  //10000000000000000000000000001010
18. //  printf("%d\n", i + j);
19. //  return 0;
20. //}


例四


这里呢由于我们 i 是unsigned int,所 i 是恒大于0的,所以这个函数为死循环


例五


1. //unsigned char i = 0;//0~255
2. //
3. //int main()
4. //{
5. // for (i = 0; i <= 255; i++)
6. // {
7. //   printf("hello world\n");
8. // }
9. // return 0;
10. //}

 

这里同理,无符号char取值范围为0~255,所以此题也是一个死循环

关于浮点数,博主会在下一篇进行介绍。

制作不易,记得一件三连哦!!!

目录
打赏
0
0
0
0
28
分享
相关文章
kafka 的数据是放在磁盘上还是内存上,为什么速度会快?
Kafka的数据存储机制通过将数据同时写入磁盘和内存,确保高吞吐量与持久性。其日志文件按主题和分区组织,使用预写日志(WAL)保证数据持久性,并借助操作系统的页缓存加速读取。Kafka采用顺序I/O、零拷贝技术和批量处理优化性能,支持分区分段以实现并行处理。示例代码展示了如何使用KafkaProducer发送消息。
C 语言结构体与位域:高效数据组织与内存优化
C语言中的结构体与位域是实现高效数据组织和内存优化的重要工具。结构体允许将不同类型的数据组合成一个整体,而位域则进一步允许对结构体成员的位进行精细控制,以节省内存空间。两者结合使用,可在嵌入式系统等资源受限环境中发挥巨大作用。
131 12
数据在内存中的存储方式
本文介绍了计算机中整数和浮点数的存储方式,包括整数的原码、反码、补码,以及浮点数的IEEE754标准存储格式。同时,探讨了大小端字节序的概念及其判断方法,通过实例代码展示了这些概念的实际应用。
278 1
“四两拨千斤” —— 1.2MB 数据如何吃掉 10GB 内存
一个特殊请求引发服务器内存用量暴涨进而导致进程 OOM 的惨案。
129 14
JVM实战—2.JVM内存设置与对象分配流转
本文详细介绍了JVM内存管理的相关知识,包括:JVM内存划分原理、对象分配与流转、线上系统JVM内存设置、JVM参数优化、问题汇总。
JVM实战—2.JVM内存设置与对象分配流转
JVM简介—2.垃圾回收器和内存分配策略
本文介绍了Java垃圾回收机制的多个方面,包括垃圾回收概述、对象存活判断、引用类型介绍、垃圾收集算法、垃圾收集器设计、具体垃圾回收器详情、Stop The World现象、内存分配与回收策略、新生代配置演示、内存泄漏和溢出问题以及JDK提供的相关工具。
JVM简介—2.垃圾回收器和内存分配策略
JVM简介—1.Java内存区域
本文详细介绍了Java虚拟机运行时数据区的各个方面,包括其定义、类型(如程序计数器、Java虚拟机栈、本地方法栈、Java堆、方法区和直接内存)及其作用。文中还探讨了各版本内存区域的变化、直接内存的使用、从线程角度分析Java内存区域、堆与栈的区别、对象创建步骤、对象内存布局及访问定位,并通过实例说明了常见内存溢出问题的原因和表现形式。这些内容帮助开发者深入理解Java内存管理机制,优化应用程序性能并解决潜在的内存问题。
JVM简介—1.Java内存区域
|
22天前
|
JVM: 内存、类与垃圾
分代收集算法将内存分为新生代和老年代,分别使用不同的垃圾回收算法。新生代对象使用复制算法,老年代对象使用标记-清除或标记-整理算法。
23 6
深入探索Java虚拟机(JVM)的内存管理机制
本文旨在为读者提供对Java虚拟机(JVM)内存管理机制的深入理解。通过详细解析JVM的内存结构、垃圾回收算法以及性能优化策略,本文不仅揭示了Java程序高效运行背后的原理,还为开发者提供了优化应用程序性能的实用技巧。不同于常规摘要仅概述文章大意,本文摘要将简要介绍JVM内存管理的关键点,为读者提供一个清晰的学习路线图。
|
4月前
|
JVM内存参数
-Xmx[]:堆空间最大内存 -Xms[]:堆空间最小内存,一般设置成跟堆空间最大内存一样的 -Xmn[]:新生代的最大内存 -xx[use 垃圾回收器名称]:指定垃圾回收器 -xss:设置单个线程栈大小 一般设堆空间为最大可用物理地址的百分之80