当前位置: 首页 > news >正文

数据在内存中的存储(1)

目录:

1.整数在内存中的存储

2.⼤⼩端字节序和字节序判断

3.浮点数在内存中的存储

正文:

1.整数在内存中的存储

整数的2进制表⽰⽅法有三种,即原码、反码和补码 三种表⽰⽅法均有符号位和数值位两部分,符号位都是⽤0表⽰“正”,⽤1表⽰“负”,⽽数值位最 ⾼位的⼀位是被当做符号位,剩余的都是数值位。

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

负整数的三种表⽰⽅法各不相同。

原码:直接将数值按照正负数的形式翻译成⼆进制得到的就是原码。

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

补码:反码+1就得到补码。

对于整形来说:数据存放内存中其实存放的是补码。 (原因:在计算机系统中,数值⼀律⽤补码来表⽰和存储。 原因在于,使⽤补码,可以将符号位和数值域统⼀处理; 同时,加法和减法也可以统⼀处理(CPU只有加法器)此外,补码与原码相互转换,其运算过程是 相同的,不需要额外的硬件电路。

2.⼤⼩端字节序和字节序判断

#include <stdio.h>
int main()
{int a = 0x11223344;return 0;
}

在这段代码中,我们调试可发现:

我们第一感觉可能是感觉有点别扭,它为什么要倒着放? 但其实也有正着放的,而倒着放的叫做小端,正着放的叫大端,接下来就是要了解什么是大端和小端:

⼤端(存储)模式:是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。

⼩端(存储)模式:是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。

那么如果让你写一个代码来判断编译器是哪种储存模式,又该怎么写呢?

代码:

详解:

创建一个整形a,给其赋值为1,如果是大端储存,a在内存中就是以00 00 00 01,这里用16进制数字表示,看起来更加方便,而小端储存就是01 00 00 00。再创建一个char类型的变量b,使b = a;这样a的第一个字节的数字就会被赋值到b中,然后打印b,如果是大端,b的结果就是0,如果是小端b就是1。

练习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;
}

答案:a=-1,b=-1,c=255

详解:-1的原码:1000 0000 0000 0000 0000 0000 0000 0001

                  反码:1111 1111 1111 1111 1111 1111 1111 1110

                  补码:1111 1111 1111 1111 1111 1111 1111 1111

把-1赋给a,a的类型是char,char的大小是1个字节 = 8个比特位,为1111 1111,(char是signed char,还是unsigned char取决于编译器,在vs中是signed char), 1111 1111整形提升后为1111 1111 1111 1111 1111 1111 1111 1111,而1111 1111 1111 1111 1111 1111 1111 1111的原码为1000 0000 0000 0000 0000 0000 0000 0001,,十进制为-1

b与a同理,也为-1;

而c是unsigned char,所以编译器会将1111 1111 1111 1111 1111 1111 1111 1111视为正数,而正数的原码,反码和补码相同,转换位十进制数字为255。

练习2:

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

答案:4294967168

详解:-128的补码:1000 0000 0000 0000 0000 0000 1000 0000

a是char类型变量,占8个比特位,1000 0000,整形提升后为1111 1111 1111 1111 1111 1111 1000 0000,%u是无符号整形的占位符,所以将1111 1111 1111 1111 1111 1111 1000 0000视为正数,十进制为4294967168。

练习3:

#include <stdio.h>
#include<string.h>
int main() 
{    char a[1000]; int i;for(i=0; i<1000; i++){a[i] = -1 - i; }    printf("%d", strlen(a)); return 0; 
}

答案:255

详解:

 我们可以换个角度理解,如图:

a[0] = -1 ,a[1] = -2, a[2] = -3……......-128       127.............. 0      -1        -2........

strlen函数遇到'\0'停止,而'\0'的ASCLL码值==0,所以会在第一个0处停止,由上可知strlen(a)==255。

练习4:

#include <stdio.h>
int main() 
{    unsigned int i;   
for(i = 9; i >= 0; i--) 
{        printf("%u\n",i);    }  
return 0; 
}

此代码是无限循环,问题在于 i 被定义为 unsigned int 类型,而循环条件 i >= 0 使用了无符号整数。在 C 语言中,无符号整数永远不会小于零,因此当 i 递减到 0 后,下一次循环 i 将变为一个非常大的正数,而不是 -1。

练习5:

//在小端储存模式中
#include <stdio.h> 
int main() 
{    int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf("%x,%x", ptr1[-1], *ptr2);
return 0;}

答案:4,200000

详解:在我们的深入理解指针的博客中提到过,&a是取出整个数组的地址,所以:

而ptr1[-1]等价于*(ptr1 - 1),ptr1是int*类型的指针,-1向后移动四个字节,指向4的地址;

而在(int *)((int)a + 1)中,,a被强制转换为了int类型,假设a数组的首元素地址是0x01ff1120,加一之后就变成了0x01ff1121,如图:

 打印*ptr2,从图上的位置开始往后四个字节,也就是0x02 00 00 00,打印出来就是200000。

 

相关文章:

  • Linux/Ubuntu/Debian从控制台启动程序隐藏终端窗口
  • 星舰第三次试飞成功,见证历史:火箭一响,下跌万两
  • DVWA靶场搭建
  • 前端之用HTML弄一个古诗词
  • OpenAI 的 GPTs 提示词泄露攻击与防护实战:攻击卷(一)
  • 【海贼王的数据航海】排序——概念|直接插入排序|希尔排序
  • 软件测试面试都问了什么?中级软件测试岗面试(4面)
  • Java的SPI机制与实例
  • C语言内存函数详解
  • 停车场车辆统计C卷(JavaPythonC++Node.jsC语言)
  • 如何关闭 Visual Studio 双击异常高亮
  • 基于高德地图JS API实现Vue地图选点组件
  • JavaSE-----认识异常【详解】
  • 鸿蒙Harmony应用开发—ArkTS声明式开发(容器组件:Tabs)
  • 【ArcGISPro】道路数据下载并使用
  • ----------
  • @jsonView过滤属性
  • angular组件开发
  • Apache Spark Streaming 使用实例
  • AWS实战 - 利用IAM对S3做访问控制
  • Bytom交易说明(账户管理模式)
  • ES6系统学习----从Apollo Client看解构赋值
  • java中的hashCode
  • Linux链接文件
  • Linux中的硬链接与软链接
  • php中curl和soap方式请求服务超时问题
  • Python 反序列化安全问题(二)
  • React的组件模式
  • spring security oauth2 password授权模式
  • 大快搜索数据爬虫技术实例安装教学篇
  • 发布国内首个无服务器容器服务,运维效率从未如此高效
  • 搞机器学习要哪些技能
  • 技术发展面试
  • 前端js -- this指向总结。
  • 实现菜单下拉伸展折叠效果demo
  • 移动端 h5开发相关内容总结(三)
  • hi-nginx-1.3.4编译安装
  • (1/2) 为了理解 UWP 的启动流程,我从零开始创建了一个 UWP 程序
  • (2022版)一套教程搞定k8s安装到实战 | RBAC
  • (23)Linux的软硬连接
  • (cljs/run-at (JSVM. :browser) 搭建刚好可用的开发环境!)
  • (C语言)输入自定义个数的整数,打印出最大值和最小值
  • (二)斐波那契Fabonacci函数
  • (附源码)springboot 个人网页的网站 毕业设计031623
  • (六)激光线扫描-三维重建
  • (顺序)容器的好伴侣 --- 容器适配器
  • (一) springboot详细介绍
  • **PHP二维数组遍历时同时赋值
  • .NET 6 在已知拓扑路径的情况下使用 Dijkstra,A*算法搜索最短路径
  • .NET CLR Hosting 简介
  • .Net Redis的秒杀Dome和异步执行
  • .NET 事件模型教程(二)
  • .NET 中的轻量级线程安全
  • .NET面试题解析(11)-SQL语言基础及数据库基本原理
  • /etc/apt/sources.list 和 /etc/apt/sources.list.d