C语言底层学习(4.数据在内存中的存储)


前言:

有人说学编程其实就是在学内存,如果对内存的理解不够就很容易写出莫名其妙的代码,导致错误的结果,今天我们就来看一下我们常见的一些数据,如:整数和浮点数在内存中是如何存储的,感兴趣的小伙伴快来围观吧~

注意:

本篇的练习解析全部都放在了《配套《数据在内存中的存储》》


文章目录

    • 前言:
    • 注意:
    • 正文:
      • [1. 整数在内存中的存储](#1. 整数在内存中的存储)
        • [1.1 二进制与原、反、补码](#1.1 二进制与原、反、补码)
        • [1.2 大小端字节序](#1.2 大小端字节序)
        • [1.3 为什么有⼤⼩端?](#1.3 为什么有⼤⼩端?)
        • [1.4 练习](#1.4 练习)
          • [1.4.1 练习1](#1.4.1 练习1)
          • [1.4.2 练习2](#1.4.2 练习2)
          • [1.4.3 练习3](#1.4.3 练习3)
          • [1.4.4 练习4](#1.4.4 练习4)
          • [1.4.5 练习5](#1.4.5 练习5)
          • [1.4.6 练习6](#1.4.6 练习6)
          • [1.4.7 练习7](#1.4.7 练习7)
          • [1.4.8 练习8](#1.4.8 练习8)
      • [2. 浮点数在内存中的储存](#2. 浮点数在内存中的储存)
        • [2.1 浮点数如何在内存里存储](#2.1 浮点数如何在内存里存储)
          • [2.1.1 练习9](#2.1.1 练习9)
          • [2.1.2 详细说明:](#2.1.2 详细说明:)

正文:

1. 整数在内存中的存储

1.1 二进制与原、反、补码

之前已经在《二进制与原、反、补码》中讲解过整数为什么要有二进制,并且计算机中的整数都是以补码的形式存储的

大家可以自行跳转《二进制与原、反、补码》查看

1.2 大小端字节序

在详细的讲解什么是大小端字节序之前,我们先来看一个代码调试中容易被忽略的小细节:

很容易就能发现这里的地址由低到高位是44 33 22 11 排序的,然后这里的a由低位(可以理解为二进制的个位)到高位也是44 33 22 11 排序的,我们把这种排序方式称为小端字节序

反之,如果地址由低到高位是11 22 33 44 的话,则称为大端字节序

具体概念为:

  • ⼤端(存储)模式:
    是指数据的低位字节内容保存在内存的⾼地址处,⽽数据的⾼位字节内容,保存在内存的低地址处。
  • ⼩端(存储)模式:
    是指数据的低位字节内容保存在内存的低地址处,⽽数据的⾼位字节内容,保存在内存的⾼地址处。
1.3 为什么有⼤⼩端?

为什么会有⼤⼩端模式之分呢?

  • 这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着⼀个字节,⼀个字节为8bit位,但是在C语⾔中除了8bit的 char 之外,还有16bit的 short 型,32bit的 long 型(要看具体的编译器),另外,对于位数⼤于8位的处理器,例如16位或者32位的处理器,由于寄存器宽度⼤于⼀个字节,那么必然存在着⼀个如何将多个字节安排的问题。因此就导致了⼤端存储模式和⼩端存储模式。
  • 例如:⼀个 16bit 的 shortx ,在内存中的地址为 0x0010x 的值为 0x1122 ,那么
    0x11 为⾼字节, 0x22 为低字节。对于⼤端模式,就将 0x11 放在低地址中,即 0x0010 中,0x22 放在⾼地址中,即 0x0011 中。⼩端模式,刚好相反。我们常⽤的 X86 结构是⼩端模式,⽽KEIL C51 则为⼤端模式。很多的ARM,DSP都为⼩端模式。有些ARM处理器还可以由硬件来选择是⼤端模式还是⼩端模式。
1.4 练习
1.4.1 练习1
  • 请设计⼀个⼩程序来判断当前机器的字节序

很显然,对于这题来说,要想知道字节序,只需要识别一下最小和最大的地址处的字节大小就好了
例如:

c 复制代码
int main()
{
	int a = 0x11223344;
	if (*(char*)&a > *((char*)&a+3))//假设低处地址是44(即小端模式)
	{
		printf("小端");
	}
	else
	{
		printf("大端");
	}
	return 0;
}

在x86环境下,运行结果为:

c 复制代码
小端

或者换一种方法:

c 复制代码
//代码1 
#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 
int check_sys()
{
 union
 {
 int i;
 char c;
 }un;
 un.i = 1;
 return un.c;
}
//代码2为代码1的化简版
1.4.2 练习2
c 复制代码
#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;
}

运行结果:

c 复制代码
a=-1,b=-1,c=255
1.4.3 练习3
c 复制代码
#include <stdio.h>
int main()
{
 char a = -128;
 printf("%u\n",a);
 return 0;
}

运行结果:

c 复制代码
4294967168
1.4.4 练习4
c 复制代码
#include <stdio.h>
int main()
{
 char a = 128;
 printf("%u\n",a);
 return 0;
}

运行结果:

c 复制代码
4294967168
1.4.5 练习5
c 复制代码
#include <stdio.h>
int main()
{
	char a[1000];
	int i;
	for(i=0; i<1000; i++)
	{
		a[i] = -1-i;
	}
	printf("%d",strlen(a));
	return 0;
}

运行结果:

c 复制代码
255
1.4.6 练习6
c 复制代码
#include <stdio.h>
unsigned char i = 0;
int main()
{
 for(i = 0;i<=255;i++)
 {
 printf("hello world\n");
 }
 return 0;
}

运行结果:

c 复制代码
hello world
hello world
hello world
...
//死循环
1.4.7 练习7
c 复制代码
#include <stdio.h>
int main()
{
 unsigned int i;
 for(i = 9; i >= 0; i--)
 {
 printf("%u\n",i);
 }
 return 0;
}

运行结果:

c 复制代码
//对于运行结果想必大家也猜到了
9
8
7
6
5
4
3
2
1
0
4294967295
4294967294
//...循环
1.4.8 练习8
c 复制代码
#include <stdio.h>
//X86环境 ⼩端字节序 
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;
 //%x意思是16进制输出
}

运行结果:

c 复制代码
4,2000000

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

2.1 浮点数如何在内存里存储
2.1.1 练习9
c 复制代码
#include <stdio.h>
int main()
{
 int n = 9;
 float *pFloat = (float *)&n;
 printf("n的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 *pFloat = 9.0;
 printf("num的值为:%d\n",n);
 printf("*pFloat的值为:%f\n",*pFloat);
 return 0;
}

运行结果:

c 复制代码
n的值为:9
*pFloat的值为:0.000000
num的值为:1091567616
*pFloat的值为:9.000000
2.1.2 详细说明:

说明:

根据国际标准IEEE(电⽓和电⼦⼯程协会)754,任意⼀个⼆进制浮点数V可以表⽰成下⾯的形式:

IEEE 754规定:

  • 对于32位的浮点数,最⾼的1位存储符号位S,接着的8位存储指数E,剩下的23位存储有效数字M
  • 对于64位的浮点数,最⾼的1位存储符号位S,接着的11位存储指数E,剩下的52位存储有效数字M

即:


如图,float类型浮点数在内存中是这样分配的

相关推荐
952363 小时前
数据结构—双链表
c语言·开发语言·数据结构·学习
能不能别报错3 小时前
K8s学习笔记(十二) volume存储卷
笔记·学习·kubernetes
报错小能手3 小时前
linux学习笔记(13)文件操作
linux·笔记·学习
知识分享小能手4 小时前
微信小程序入门学习教程,从入门到精通,WXML(WeiXin Markup Language)语法基础(8)
前端·学习·react.js·微信小程序·小程序·vue·个人开发
LadyKaka2264 小时前
【IMX6ULL驱动学习】PWM驱动
linux·stm32·单片机·学习
MYX_3094 小时前
第四章 神经网络的学习
python·神经网络·学习
胖咕噜的稞达鸭5 小时前
算法入门:专题攻克主题一---双指针(1)移动零 复写零
c语言·开发语言·c++·算法
一只小bit6 小时前
CMake 入门实战手册:从理解原理开始,打造高效 C/C++ 开发流程
c语言·开发语言·c++·cmake
你赖东东很不错嘛_6 小时前
【C语言】char * 、char [ ]、const char * 和 void *的使用以及区别
c语言