Hylicos --- krprint实现

news2024/9/23 21:20:31

可变参函数的工作原理

函数调用时先用寄存器R0 ~R3 存放参数,如果不够放还要使用到堆栈,参数列表的形参从右到左依次入栈,弹栈时就是从左到右的顺序。
如果函数参数的个数固定,编译器就可以很清楚地在函数运行时依次从堆栈中弹出多少个参数压栈,清楚使用参数时弹栈多少个参数。
如果函数参数不固定,编译器就不知道参数的个数了,入栈弹栈时也就不知道操作多少个参数了。

所以使用可变参函数应该携带参数个数信息:void foo(int n, ...);
通常将个数信息放在可变参函数列表中的第一个,入栈时会保存在栈顶,使用参数时,弹栈的第一个参数就是个数信息了!
像printf这样的函数,第一个参数是字符串,其实其中包含了更多信息:打印格式,打印信息,还有我们说必须的 可变参个数的信息

标准可变参函数的实现

va_list就是定义一个变参变量argv
va_start宏获取可变参数列表的第一个参数的确切地址,赋值给argv变量,argv成功指向函数test_vparameter参数堆栈的栈顶
va_arg(argv, int) 每次运行都让指向argv的指针像栈底方向偏移一个int类型的长度。
va_arg让指向argv的指向指向栈底的时候就要调用va_end(argv)结束对va_list变量的操作
在这里插入图片描述

void test_num(int num){
    *(char *)0xd0000020=num+'0';
}

void test_vparameter(int i,...){
    int c;
    va_list argv;
    va_start(argv,i);
    while(i--){
        c=va_arg(argv,int);
        test_num(c);
    }
    va_end(argv);
}

实现细节

   typedef char* va_list;
   #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&(sizeof(int)-1))
   #define va_start(ap,v)    ( ap = (va_list)&v + _INTSIZEOF(v))
   #define va_arg(ap,t)  (*(t*)((ap+=_INTSIZEOF(t)) - _INTSIZEOF(t)))
   #define va_end(ap)    ( ap = (va_list)0 )

其中

_INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int)-1))

1.~是位取反的意思。 ~(sizeof(int) - 1) )就应该为 ~(4-1)= ~(00000011b)=11111100b,这样任何数& ~(sizeof(int) - 1) )后最后两位肯定为0,就肯定是4的整数倍了。

2.(sizeof(n) + sizeof(int) - 1)就是将大于4m但小于等于4(m+1)的数提高到大于等于4(m+1)但小于4(m+2),这样再& ~(sizeof(int) - 1) )后就正好将原长度补齐到4的倍数了。

用来计算各种数据类型按照4字节对齐后的结果

va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v))

va_start(ap,v)实际上就是在对变量ap进行赋值,其值为变量v的地址加上v的类型按照4字节对齐后的偏移。因为参数在内存中的分布是连续的,又因为传递给宏va_start的参数v都是变参函数里可变参数列表中的前一个参数。所以,变量ap最终的结果是一个指向变参列表首地址的指针。

va_arg(ap,t) ((t)((ap+=_INTSIZEOF(t)) - _INTSIZEOF(t)))

宏va_arg(ap,t)中的参数t只能输入变量类型,该宏恰恰也是根据变量的类型来正确提取参数的。首先,宏va_arg将变量ap的值在原有的基础上加上一个对齐后的偏移,此时,ap已经指向变参到表中的下一个变量了,然后表达式在减去一个同样的值后被强行转成t类型,此时我们正好取出了变量ap所指向的那个参数,同时更新变量ap,让它指向参数列表中的下一个参数以便下次使用。

va_end(ap) ( ap = (va_list)0 )

va_end(ap)将变量ap赋值为零,从此不再使用

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

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

相关文章

关于城市旅游的HTML网页设计 HTML+CSS上海博物馆网站 dreamweaver作业静态HTML网页设计 html网页制作期末大作业

👨‍🎓静态网站的编写主要是用 HTML DⅣV CSSJS等来完成页面的排版设计👩‍🎓,一般的网页作业需要融入以下知识点:div布局、浮动定位、高级css、表格、表单及验证、js轮播图、音频视频Fash的应用、uli、下拉…

JVM--这一篇就够了

1、JVM内存模型 Java内存模型是指Java虚拟机的内存模型,我们来看下Java内存模型的图片: 其中,在JAVA的JVM调优中,我们JAVA程序员需要重点关注的,首先是堆,我们看下堆内存的内存模型: 2、类的加载过程 (1)、加载 …

基于jsp+ssm的高速公路收费管理系统-计算机毕业设计

项目介绍 现阶段,政府都会对高速公路收费进行管理,用户通过进入相关系统对高速公路收费状况进行了解,简化了高速公路收费管理流程,进而提高政府高速收费管理效率,达到更好的管理目的。 本设计利用JSP作为开发语言。后…

Nature Communications:人类大脑的皮层下-皮层的动态状态及其在中风中的损伤

摘要 控制大脑自发活动中的动态模式的机制尚不清楚。在这里&#xff0c;我们提供的证据表明&#xff0c;在超低频率范围内&#xff08;<0.01-0.1Hz&#xff09;的皮层动力学需要完整的皮层-皮层下通信。利用静息态功能磁共振成像&#xff08;fMRI&#xff09;&#xff0c;我…

2021-2022 ICPC, NERC, Northern Eurasia Onsite L. Labyrinth

翻译&#xff1a; 莱斯利和利昂进入了一个迷宫。迷宫由&#x1d45b;大厅和&#x1d45a;大厅之间的单向通道组成。大厅编号从1到&#x1d45b;。 莱斯利和利昂在大厅开始了他们的旅程&#x1d460;。他们立刻争吵起来&#xff0c;决定各自去探索迷宫。然而&#xff0c;他们希…

分享一个你很可能不知道的Java异常实现的缺陷

前言 Java中一个大家熟知的知识点就是异常捕获&#xff0c;try…catch…finally组合&#xff0c;但是很多人不知道这里面有一个关于Java的缺陷&#xff0c;或者说是异常实现的一点不足之处。 我这边就通过一个很简单的实验给大家演示下效果玩玩儿&#xff0c;希望大家能觉得有趣…

linux搭建测试环境(tomcat)

安装jdk 1,查看是否装的有&#xff08;centos7会自带的有&#xff09;如果是普通用户切记要切换到root 输入命令查看是否安装&#xff1a; java -version2,跟踪查看自带jdk 默认安装了openjdk&#xff0c;那就要知道具体文件安装到哪里了&#xff0c;这里我们可以通过命令“rp…

黑马程序员Java数据结构与java算法笔记(1)

数据结构和算法详细内容 来源&#xff1a;黑马程序员Java数据结构与java算法 1.数据结构和算法概述 1.1什么是数据结构&#xff1f; 数据结构就是把数据元素按照一定的关系组织起来的集合&#xff0c;用来组织和存储数据 1.2数据结构分类 传统上&#xff0c;我们可以把数…

跟我学Python图像处理丨图像分类原理与案例

摘要&#xff1a;本篇文章将分享图像分类原理&#xff0c;并介绍基于KNN、朴素贝叶斯算法的图像分类案例。本文分享自华为云社区《[Python图像处理] 二十六.图像分类原理及基于KNN、朴素贝叶斯算法的图像分类案例丨【百变AI秀】》&#xff0c;作者&#xff1a;eastmount 。 一…

5-4:发送系统通知

触发事件 评论后&#xff0c;发布通知点赞后&#xff0c;发布通知关注后&#xff0c;发布通知。 处理事件 封装事件对象开发事件的生产者开发事件的消费者 消费者线程&#xff1a;从队列里读消息&#xff0c;并做处理&#xff1b; 生产者线程&#xff1a;往线程中存入数据&…

深度神经网络是什么意思,神经网络准确度只有50

1、研究人工神经网络的权值分布有什么意义 神经网络一般都是非常庞大的&#xff0c;每个边对应一个权值&#xff0c;如果权值不共享的话&#xff0c;数据量就更大了&#xff0c;但是为了提高效率&#xff0c;引入了权值共享&#xff0c;但是还不够&#xff0c;想再次提高效率和…

五、伊森商城 前端基础-Vue Vue脚手架创建 p26

目录 一、vue 模块化开发 1、全局安装 webpack 2、全局安装 vue 脚手架vue-cli 3、初始化 vue 项目 3.1、创建文件夹 3.2、初始化vue脚手架 3.3、项目结构 4、项目启动命令 拓展&#xff1a;创建超时 一、vue 模块化开发 打开终端&#xff0c;进行命令安装 1、全局安装…

Linux网络基础(初级)

Linux网络基础 文章目录Linux网络基础1.计算机网络的发展过程1.1 独立模式1.2 网络互联模式1.3 局域网 LAN1.4 广域网 WAN2.计算机网络协议2.1 协议的概念2.2 什么是网络协议2.3 什么是网络协议簇2.4 OSI 七层模型2.5 TCP/IP 五层模型3.网络传输基本流程3.1 同局域网内的两台主…

[附源码]计算机毕业设计拉勾教育课程管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

实例解析丨一文搞定GaussDB CM服务异常

摘要&#xff1a;本文主要为大家带来如何处理GaussDB CM服务异常问题。本文分享自华为云社区《【实例状态】GaussDB CM服务异常》&#xff0c;作者&#xff1a;酷哥。 首先确认是否是虚拟机、网络故障&#xff0c;底层故障处理 PID文件未清理导致进程启动失败 问题现象 收到…

FS2115D SOT23-6 低噪声3.3V升压IC电荷泵 DC/DC 转换器

概述 FS2115D 是一款低噪声、恒定频率 &#xff08;1.2MHz&#xff09; 开关电容倍压器。它从 1.8V 至 5V 输入产生一个稳定的输出电压&#xff0c;输出电流高达 150mA。FS2115D 的外部元件数量少&#xff08;VIN 和 VOUT 处有一个跨接电容器和两个小型旁路电容器&#xff09;…

程序员看世界杯

目录 1、世界杯赛事规则 1.1、赛制 1.2、小组赛 1.3、淘汰赛阶段 1.4、1/8决赛 1.5、半决赛 1.6、决赛 2、大力神杯材质 3、看球心德 4、2022大力神杯赢家 1、世界杯赛事规则 1.1、赛制 世界杯一共进行64场&#xff0c;其中分小组赛48场&#xff0c;1/8决赛8场&am…

Sentinel--服务容错

目录一、高并发带来的问题二、服务雪崩效应三、常见容错方案四、Sentinel入门什么是Sentinel安装Sentinel控制台实现一个接口的限流五、Sentinel的概念和功能基本概念重要功能六、Sentinel规则流控规则简单配置配置流控模式配置流控效果降级规则热点规则授权规则系统规则自定义…

行为管理(锐捷行业网关篇)

大家好&#xff0c;我是小杜。有了自学习和师傅指导这个“buff”&#xff0c;感觉自己的进步是“一日千里”啊&#xff01; 今天来学习网关产品的行为管理相关的配置&#xff0c;咦&#xff0c;网关EG系列和睿易的NBR-E系列的路由器差不多啊&#xff0c;难道是“双胞胎”&#…

安卓app源码和设计报告——简易记账本

课 程 设 计&#xff08;实训&#xff09;说 明 书 题目实现简易记账本功能 专 业班 级学生姓名同组学生指导老师课程设计&#xff08;实训&#xff09;评语 学生姓名 专业 班级 2 题目 实现简易记账本功能 评语&#xff1a; 成绩&#xff1a; 优良中及格不及格出勤20%实…