C语言指针及数组的运行原理

news2025/1/14 4:12:49

C语言指针及数组的运行原理

文章目录

  • C语言指针及数组的运行原理
    • 一. 指针(汇编角度)
    • 二. 数组(汇编角度)
      • 2.1 数组的定义
      • 2.2 指针与数组结合
    • 三. 指令解释参考
      • 3.1 nop
      • 3.2 leave
      • 3.3 ret

这里涉及汇编,虚拟机这边采用的是64位,Intel架构,汇编语法是AT&T。

一. 指针(汇编角度)

编写一个指针调用程序的C语言文件pointer.c

这里我声明了一个函数test

*代表运用指针,int来指定指针所操作内存单元大小

主函数这边,我声明了一个变量num,并赋值。调用test函数,通过&符号来提取num地址值并传参。

#include <stdio.h>

void test(int *p){
	*p = 3;

};
int main(){
	int num = 1;
	test(&num);
	return 1;
}

编译C文件,生成汇编

// -S 只进行编译
// -fno-asynchronous-unwind-tables 过滤调试代码
[root@localhost practice]# gcc -S -fno-asynchronous-unwind-tables pointer.c

查看生成的汇编文件pointer.s

	.file	"pointer.c"
	.text
	.globl	test
	.type	test, @function
test:
	pushq	%rbp				// 开辟栈空间,栈基址bp指向该空间地址
	movq	%rsp, %rbp			// 栈顶针sp指向栈基址bp所指向的空间地址
	movq	%rdi, -8(%rbp)		// rdi寄存器的值放入rbp-8字节大小的空间里
	movq	-8(%rbp), %rax		// 将rbp-8的地址值,放入rax寄存器中
	movl	$3, (%rax)			// 把3赋予这个rax所指向的地址
	nop							// 无操作
	popq	%rbp				// 还原bp
	ret							// 弹出返回地址空间,放入ip指令地址寄存器
main:
	pushq	%rbp
	movq	%rsp, %rbp
	subq	$16, %rsp			// 将sp的地址空间-16byte  
	movl	$1, -4(%rbp)		// 将1赋值到 bp-4 的空间里
	leaq	-4(%rbp), %rax		// 将该空间地址取出放入rax寄存器
	movq	%rax, %rdi			// 将rax寄存器的地址放入rdi寄存去
	call	test				// 调用test函数
	movl	$1, %eax			// 将立即数返回
	leave
	ret

总结:可通过汇编文件看出,指针通过栈空间的地址,从而找到变量单元。并且指针必须严格声明类型,因为类型进而能告诉机器他所需内存大小是多少。换句话说指针的操控=栈内存地址的操控


二. 数组(汇编角度)

2.1 数组的定义

编写一个数组定义的C文件demo.c

#include <stdio.h>

int main(){
	int arr[] = {11,22,33};
	return 1;
}

编译C文件生成汇编

// -S 只进行编译
// -fno-asynchronous-unwind-tables 过滤调试代码
[root@localhost practice]# gcc -S -fno-asynchronous-unwind-tables pointer.c

查看生成的汇编文件demo.s

	.file	"demo.c"
	.text
	.globl	main
	.type	main, @function
main:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	$11, -12(%rbp)  // 将11存储到rbp-12的空间里
	movl	$22, -8(%rbp)	// 将22存储到rbp-8的空间里
	movl	$33, -4(%rbp)	// 将33存储到rbp-4的空间里
	movl	$1, %eax
	popq	%rbp
	ret

总结:不难通过上述汇编文件demo.s看出,定义的值分别放入栈空间里,并且按照低地址到高地址,依次放入。

2.2 指针与数组结合


编写一个指针与数组结合的C文件demo2.c

这里我编写了一个长度为3的数组,放入的是int类型

让指针取最后一个索引数组值

#include <stdio.h>

int main(){
	int arr[] = {11,22,33};
	int *p = &arr[2];
	return 1;
}

编译并生成汇编代码(上面步骤提及,不在重复)

	.file	"demo3.c"
	.text
	.globl	main
	.type	main, @function
main:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	$11, -20(%rbp)
	movl	$22, -16(%rbp)
	movl	$33, -12(%rbp)
	
	leaq	-20(%rbp), %rax  // 将bp-20的地址(可理解为arr[0]的地址)放入rax寄存器
	addq	$8, %rax		// 将rax的地址值加8byte大小(可理解为加完后变成arr[2]),并重新让如rax寄存器中
	movq	%rax, -8(%rbp)	// 将rax地址保存到 rbp-8的位置上
	movl	$1, %eax
	popq	%rbp
	ret

总结:通过将数组里各个索引下标,转换成地址值,供指针操作。

⭐️额外的一些指针与数组的操作

1.通过指针改变数组里的值

#include <stdio.h>

int main(){
	int arr[] = {11,22,33};
	int *p = &arr[2];
	*p = 44;
	return 1;
}
------
    .file	"demo4.c"
	.text
	.globl	main
	.type	main, @function
main:
	pushq	%rbp
	movq	%rsp, %rbp
	movl	$11, -20(%rbp)
	movl	$22, -16(%rbp)
	movl	$33, -12(%rbp)
        
	leaq	-20(%rbp), %rax
	addq	$8, %rax
	movq	%rax, -8(%rbp)
	movq	-8(%rbp), %rax
	movl	$44, (%rax)     // 改变数组指定下标为2的数值
	movl	$1, %eax
	popq	%rbp
	ret

2.通过指针的内存加减获取数组的值

#include <stdio.h>

int main(){
	int arr[] = {11,22,33};
	int *p = &arr[0]; //获取首个索引的4字节地址,
	int a = *(p+1);  // 获取第二个4字节地址
	return 1;
}
------------
    .file	"demo5.c"
	.text
	.globl	main
	.type	main, @function
main:
	pushq	%rbp
	movq	%rsp, %rbp
	
	movl	$11, -24(%rbp)
	movl	$22, -20(%rbp)
	movl	$33, -16(%rbp)
	
	leaq	-24(%rbp), %rax  //取地址
	
	movq	%rax, -8(%rbp)
	movq	-8(%rbp), %rax
	movl	4(%rax), %eax //rax地址值是-24(%rbp) ,加4字节后,变成了数组中第二个值
	movl	%eax, -12(%rbp)
	movl	$1, %eax
	popq	%rbp
	ret

三. 指令解释参考

3.1 nop

运行该指令时什么都不做,但是会占用一个指令的时间。

当指令间需要有延时(给外部设备足够的响应时间;或是软件的延时等),可以插入“NOP”指令。

Intel手册 Volume2 Chapter4.3

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-8yJRSL1P-1681886307021)(C语言指针及数组的运行原理.assets/屏幕截图 2023-04-19 140238.png)]

3.2 leave

释放分配的栈空间,并还原bp,sp到原始指向的地址空间

Intel手册 Volume1 Chapter6.6.2

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-0aUguHbo-1681886307022)(C语言指针及数组的运行原理.assets/屏幕截图 2023-04-19 140821.png)]

3.3 ret

删除由调用程序推送到堆栈上的任何参数和返回地址

Intel手册 Volume2 Chapter4.3
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/435829.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

如何在 Google Cloud 上部署 EMQX 企业版

Google Cloud 的 IoT Core 产品将于 2023 年 8 月 16 日停止服务&#xff0c;随着这一日期的临近&#xff0c;许多用户正在为他们现有的物联网业务寻找新的解决方案&#xff0c;而 EMQX 企业版是实现这一目标的理想选择。 EMQX 企业版是一款大规模分布式 MQTT 消息服务平台&am…

【设计模式】深入浅出--外观模式

文章目录 前言一、外观模式介绍二、案例场景三、外观模式优缺点四、外观模式应用场景总结 前言 不知道大家有没有比较过自己泡茶和去茶馆喝茶的区别&#xff0c;如果是自己泡茶需要自行准备茶叶、茶具和开水&#xff0c;而去茶馆喝茶&#xff0c;最简单的方式就是跟茶馆服务员…

高效的配置文件读取工具支持properties和yaml

JefConfig 前言 日常工作中不知道到大家有没有遇到以下几种情况&#xff1a; 1、在程序启动时需要加载配置文件&#xff0c;但是发现程序只能从固定位置读取配置文件。 2、程序在集成了spring框架后&#xff0c;想从配置文件中获取某个配置&#xff0c;但是发现当前程序并未交…

并查集原理及代码实现

并查集 首先要明确的是并查集是森林。由多棵树组成。 并查集 &#xff08;英文&#xff1a;Disjoint-set data structure&#xff0c;直译为不交集数据结构&#xff09;&#xff0c;用于处理一些 不交集 &#xff08;Disjoint sets&#xff0c;一系列没有重复元素的集合&…

android framework-SystemServer进程

SystemServer进程信息 一、SystemServer整体时序图 涉及源码路径&#xff1a; android-10.0.0_r41\frameworks\base\core\java\com\android\internal\os\ZygoteInit.java android-10.0.0_r41\frameworks\base\core\java\com\android\internal\os\Zygote.java android-10.0.0_r4…

JAVAWeb07-WEB 开发通信协议-HTTP 协议-关联篇

1. 概述 1.1 官方文档及示例说明 1.1.1 请求头 1.1.2 响应头 1.1.3 HTTP 响应状态码 HTTP状态码 当浏览者访问一个网页时&#xff0c;浏览者的浏览器会向网页所在服务器发出请求。当浏览器接收并显示网页前&#xff0c;此网页所在的服务器会返回一个包含HTTP状态码的信息头&a…

leetcode 1372. Longest ZigZag Path in a Binary Tree(二叉树中最长的之字形路径)

找出最长的之字型路径长度。 可以选择从二叉树的任意一个节点出发。 路径长度为路径中的节点数-1. 思路&#xff1a; 符合DFS的特征。 方向是左右交替的&#xff0c;可以定义0&#xff0c;1两个方向。 如果当前方向是左&#xff0c;下一方向就是右&#xff0c;反之亦然。每次…

FinClip|小程序云开发的那点事儿

在开发一个小程序时&#xff0c;除了考虑界面功能逻辑外&#xff0c;还需要后端的数据支持&#xff0c;开发者需要提前考虑服务器、存储和数据库等相关需求的支持能力&#xff0c;此外还可能需要花费时间精力在部署应用、和依赖服务的建设上。 因此&#xff0c;微信小程序为了…

dolphinscheduler3.1.3版本代码编译运行方法

说明 该文档适用于dolphinscheduler 3.1.3-release版本。 一 环境准备 需要使用的环境包括JDK1.8&#xff0c;以及Maven 3.6以上的版本&#xff0c;这里使用低于3.6版本的Maven也可以调试运行&#xff0c;不过在打包的时候会有报错&#xff0c;最好使用高版本的maven。 二 …

数字IC笔试面试常考问题及答案汇总(内含各岗位大厂题目)

经历了无数的笔试面试之后&#xff0c;不知道大家有没有发现数字IC的笔试面试还是有很多共通之处和规律可循的。所以一定要掌握笔试面试常考的问题。 数字IC笔试面试常考问题及答案汇总&#xff08;文末可领全部哦~&#xff09; 验证方向&#xff08;部分题目&#xff09; Q1…

android studio APP工程的项目结构说明及创建

目录 1.APP工程的项目结构图 2.功能说明 2.1app 2.2Gradle Scripts 3.创建新的APP页面 补充&#xff1a; 1.APP工程的项目结构图 2.功能说明 该项目下两个分类&#xff1a;一个是app&#xff08;代表app模块&#xff09;;另一个是Gradle Scripts。 2.1app app下面有3个…

虚拟机安装Centos7,ping不通百度

虚拟机安装Centos7&#xff0c;ping不通百度 一、虚拟机网络配置 网络适配器选择桥接模式&#xff0c;不勾选复制物理网络连接状态。 同时虚拟机使用默认配置都是桥接。 二、配置静态IP 1、首先&#xff0c;查看宿主机的IP和网关 2、配置静态ip的文件地址及修改命令如下&…

mybatis分页插件的基本理解和使用

mybatis分页插件的基本理解和使用 为什么要使用mybatis分页插件&#xff1f; 分页是一种将所有数据分段展示给用户的技术。用户每次看到的不是全部数据&#xff0c;而是其中一部分&#xff0c;如果在其中没有找到自己想要的内容&#xff0c;用户可以通过制定页码或者是翻页的…

就业并想要长期发展选数字后端还是ic验证?

“就业并想要长期发展选数字后端还是ic验证&#xff1f;” 这是知乎上的一个热点问题&#xff0c;浏览量达到了13,183。看来有不少同学对这个问题感到疑惑。之前更新了数字后端&数字验证的诸多文章&#xff0c;从学习到职业发展&#xff0c;都写过&#xff0c;唯一没有做过…

CRM系统能帮助企业解决哪些问题?

随着信息化技术的不断发展和全球化的推进&#xff0c;市场竞争越来越激烈&#xff0c;客户需求也在不断变化。为了应对这种情况&#xff0c;越来越多的企业开始使用CRM系统来管理与客户的关系。那么&#xff0c;CRM系统到底解决了企业哪些问题呢&#xff1f; 一、提高客户满意…

亿发软件:传统食品饮料批发行业如何通过信息化管理系统降本增效?

传统食品饮料批发行业信息化水平较低&#xff0c;存在多重管理难题&#xff0c;例如&#xff1a; 手动数据输入和管理&#xff0c;导致错误和效率低下&#xff1b; 数据缺乏实时可见性&#xff0c;无法实时了解企业仓库存量、销售额和其他关键业务指标&#xff1b; 低效的供应链…

【Android】之【常用布局】

一、简介 Android常用布局分别是 1、线性布局LinearLayout 2、相对布局RelativeLayout 3、绝对布局AbsoluteLayout 4、帧布局FrameLayout 5、表格布局TableLayout 6、网格布局GridLayout 7、约束布局ConstraintLayout 二、详解 2.1. LinearLayout (线性布局) 线性布局是一种非…

Rabbit与springboot整合-1

目录 1、整体结构 2、pom引入 3、配置文件 4、代码 公共类 controller类 JSON转换类 监听-接收发送消息类 1、整体结构 2、pom引入 <!--rabbitmq--> <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-st…

C++引用与引用两大应用场景,临时变量的常性,常引用与权限大小问题

tips 内存栈区的用习惯是先使用高地址&#xff0c;然后使用低地址嘛顺序表数组支持随机下标访问&#xff0c;也是目前已知的仅有的数据结构类当中的话&#xff0c;它不可以不仅可以去定义变量&#xff0c;它也可以定义函数&#xff0c;这个跟c当中的结构体不一样的&#xff0c…

数据结构考研版——队列的配置问题

一、正常配置下的情况 队空状态 frontrear;入队操作 出队操作 队满状态 在正常配置下元素的个数&#xff08;rear>front&#xff09; 当rear<front 综上所述用一个表达式表示&#xff1a;(rear-frontmaxSize)%maxSize 二、非正常配置下的情况1 队空状态 入队操作…