分享

C语言指针底层原理

 山峰云绕 2022-06-04 发布于贵州

https://m.toutiao.com/is/FoGhWNt/?=C语言指针底层原理 


如果要选出C语言中最重要、难度大的概念是什么,那就是指针!难度大,意味着使用方便、实用高效,同时也意味这个知识点复杂、实用的时候容易出错。指针用的好,可以提高代码执行效率、节约系统资源;如果用的不好,程序中就会出现一定的问题。

今天我们就来聊一下指针。从最底层的内存存储空间开始,一直到应用层的各种指针使用技巧,循序渐进,以最简洁的语言进行讲解,希望能对你有一点点帮助就够了

说明:素材难找,为了偷懒和方便讲解和理解,文中配图的内存空间的地址是随便写的,在实际计算机中是要遵循地址对齐方式的。

变量与指针的本质

内存地址

我们编写一个程序源文件之后,编译得到的二进制可执行文件存放在电脑的硬盘上,此时它是一个静态的文件,一般称之为程序。

当这个程序被启动的时候,操作系统将会做下面几件事情:

·把程序的内(代码段、数据)从硬盘复制到内存中;

·创建一个数据结 PCB(进程控制),来描述这个程序的各种信息

·在代码段中定位到入口函数的地址, CPU从这个地址开始执行。

当程序开始被执行时,就变成一个动态的状态,一般称之为进程。

内存分为:物理内存和虚拟内存。操作系统对物理内存进行管理、包装,我们开发者面对的是操作系统提供的虚拟内存。

2个概念不妨碍文章的理解,因此就统一称之为内存。

在我们的程序中,通过一个变量名来定义变量、使用变量。

变量本身是一个确确实实存在的东西,变量名是一个抽象的概念,用来代表这个变量。

那么,我们定义一个变量之后,这个变量放在哪里呢?那就是内存的数据区。

内存是一个很大的存储区域,被操作系统划分为一个一个的小空间,操作系统通过地址来管理内存。

内存中的最小存储单位是字(8 bit),一个内存的完整空间就是由这一个一个的字节连续组成的。

32 64位系统

我们平时所说的计算机 3264位,指的是计算机 CPU中寄存器的最大存储长度,如果寄存器中最大存 32bit的数据,我们就叫作32位系统。

在计算机中,数据一般都是在硬盘、内存和寄存器之间进行来回存取CPU 3种总线把各组成部分联系在一起:地址总线、数据总线和控制总线。地址总线的宽度决定 CPU的寻址能力,也就 CPU能达到的最大地址范围。

刚才说了,内存是通过地址来管理的,那 CPU想从内存中的某个地址空间上存取一个数据,那 CPU就需要在地址总线上输出这个存储单元的地址。

假如地址总线的宽度 8位,能表示的最大地址空间就 256个字节,能找到内存中最大的存储单元 255这个格子。即使内存条的实际空间 2G字节CPU也没法使用后面的内存地址空间。如果地址总线的宽度 32位,那么能表示的最大地址就 2 32次方,也就 4G字节的空间。

【注意】这里只是描述地址总线的概念,实际的计算机中地址计算方式要复杂的多,比如:虚拟内存中采用分段、分页、偏移量来定位实际的物理内存,在分页中还有大页、小页之分。

变量

我们 C程序中使用变量一个数据,使用函数名一个函数,变量名和函数名是程序员使用的助记符。变量和函数最终是要放到内存中才能 CPU使用的,而内存中所有的信(代码和数)都是以二进制的形式来存储的,计算机根据就不会从格式上来区分哪些是代码、哪些是数据CPU在访问内存实际上访问地址,而不是访问变量名、函数名。

在程序代码中使用变量名来指代变量,而变量在内存中是根据地址来存放的,这二者之间是通过编译器()起来的

变量 2个重要属性:变量的类型和变量的值

示例:代码中定义了一个变量

int a = 20;

类型 int型,值 20。这个变量在内存中的存储模型为:

我们在代码中使用变量a,在程序执行的时候就表示使 0x11223344地址所对应的那个存储单元中的数据。

因此,可以理解为变量 a就等价于这个地 0x11223344。换句话说,如果我们可以提前知道编译器把变 a安排在地 0x11223344这个单元格中,我们就可以在程序中直接用这个地址值来操作这个变量。

在上图中,变 a的值 20,在内存中占据 4个格子的空间,也就 4个字节。为什么 4个字节呢? C标准中并没有规定每种数据类型的变量一定要占用几个字节,这是与具体的机器、编译器有关。

比如32位的编译器中:

char: 1个字节;

short int: 2个字节;

int: 4个字节;

long: 4个字节。

比如64位的编译器中:

char: 1个字节;

short int: 2个字节;

int: 4个字节;

long: 8个字节。

为了方便描述,下面都 32位为例,也就 int型变量在内存中占 4个字节。

另外0x112233440x112233450x112233460x11223347这连续的、从低地址到高地址 4个字节用来存储变 a的数 20

在图示中,使用十六进制来表示,十进制数 20 16进制就是0x00000014,所以从开始地址依次存 0x000x000x000x14 4个字(存储顺序涉及到大小端的问题,不影响文本理)

根据这个图示,如果在程序中想知道变 a存储在内存中的什么位置,可以使用取地址操作&,如下:

printf('&a = 0x%x \n', &a);

这句话将会打印出&a = 0x11223344

考虑一下, 32位系统中:指针变量占用几个字节?

指针变量

指针变量可以 2个层次来理解:

·指针变量首先是一个变量,所以它拥有变量的所有属性:类型和值。它的类型就是指针,它的值是其他变量的地址既然是一个变量,那么在内存中就需要为这个变量分配一个存储空间。在这个存储空间中,存放着其他变量的地址。

·指针变量所指向的数据类型,这是在定义指针变量的时候就确定的。例如int *p;意味着指针指向的是一 int型的数据。

32位系统中,一个指针变量在内存中占 4个字节的空间。因 CPU对内存空间寻址时,使用的 32位地址空( 4个字),也就是 4个字节就能存储一个内存单元的地址。而指针变量中的值存储的就是地址,所以需 4个字节的空间来存储一个指针变量的值。

示例:

int a = 20;

int *pa;

pa = &a;

printf('value = %d \n', *pa);

在内存中的存储模型如下:

4.在返回STM32CubeMX后,Pinout&Configuration里面pinout view,点击选PA8 PIN脚,在弹出的小框里面选RCC_MCO,使PA8MCOPIN脚。同样地方式,设PA1GPIO Output

5.本期先分享到这里,想要进群学习单片机编程的同学可以私信我,回我要入,与我们一起成长,喜欢的可以点个赞关注我们!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多