[C][可变参数列表]详细讲解
目录
- 1.宏含义及使用
- 2.宏原理分析
- 1.原理
- 2.宏理解
1.宏含义及使用
- 依赖库
stdarg.h va_list- 其实就是
char*类型,方便后续按照字节进行指针移动
- 其实就是
va_start(arg, num)- 使
arg指向可变参数部分(num后面)
- 使
va_arg(arg, int)- 先让
arg指向下个元素,然后使用相对位置 – 偏移量,访问当前元素- 即:访问了当前数据的同时,又让arg指向了后续元素
- 先让
va_end- 将arg指针设置为
NULL,防止野指针
- 将arg指针设置为
- 使用示例
int FindMax(int num, ...) {va_list arg;va_start(arg, num);int max = va_arg(arg, int); // 根据类型,获取可变参数列表中的第一个数据//获取并比较其他的for (int i = 0; i < num - 1; i++){int cur = va_arg(arg, int);if (max < curr){max = curr;}}va_end(arg);return max; }int main() {int max = FindMax(5,11,22,33,44,55);printf("max = %d\n", max);return 0; } - 注意事项
- 可变参数必须从头到尾逐个访问
- 如果在访问了几个可变参数之后想半途终止,这是可以的
- 但是,如果想一开始就访问参数列表中间的参数,那是不行的
- 参数列表中至少有一个命名参数
- 如果连一个命名参数都没有,就无法使用
va_start
- 如果连一个命名参数都没有,就无法使用
- 这些宏是无法直接判断实际存在参数的数量
- 这些宏无法判断每个参数的类型
- 如果在
va_arg中指定了错误的类型,那么其后果是不可预测的- 整型提升除外
- 可变参数必须从头到尾逐个访问
2.宏原理分析
1.原理
- 可变参数列表对应的函数,最终调用也是函数调用,也要形成栈帧
- 栈帧形成前,临时变量是要先入栈的,根据之前所学,参数之间位置关系是固定的
- 通过之前的汇编的学习,发现了短整型在可变参数部分,会默认进行整形提升(char short float整型提升成int/double),那么函数内部在提取该数据的时候,就要考虑提升之后的值,如果不加考虑,获取数据可能会报错或者结果不正确
2.宏理解
- 都有什么?
// va_list其实就是char*类型,方便后续按照字节进行指针移动 typedef char * va_list;#define va_start _crt_va_start #define va_arg _crt_va_arg #define va_end _crt_va_end #define va_start _crt_va_start依赖实现// 这个宏特别好理解,结合栈帧中临时参数的压入位置 #define _crt_va_start(ap,v) ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )#define va_arg _crt_va_arg依赖实现// 这个设计特别巧妙,先让ap指向下个元素,然后使用相对位置-偏移量,访问当前元素 // 访问了当前数据的同时,还让ap指向了后续元素,一举两得 #define _crt_va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )#define va_end _crt_va_end依赖实现// 这个宏特别好理解,将ap指针设置为NULL #define _crt_va_end(ap) ( ap = (va_list)0 )_ADDRESSOF(v)理解// 取参数的地址,也很好理解 #define _ADDRESSOF(v) ( &(v) )_INTSIZEOF(n)理解,难点#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )- 前提:
- 为了后面方便表述,假设
sizeof(n)的值 -->n(char 1,short 2, int 4) - 在32位平台下测试,
sizeof(int) == 4,其他情况暂时不考虑
- 为了后面方便表述,假设
_INTSIZEOF(n)的意思:计算一个最小数字x,满足x>=n && x%4==0,其实就是一种4字节对齐的方式- 是什么?
- 比如
n是:1,2,3,4 对n进行向sizeof(int)的最小整数倍取整的问题 就是 4 - 比如
n是:5,6,7,8 对n进行向sizeof(int)的最小整数倍取整的问题 就是 8
- 比如
- 为什么要有这个4字节对齐
- 结合之前栈帧的学习和上面代码的测试结果
- 怎么办到的
- 第一步理解:4的倍数
- 既然是4的最小整数倍取整,那么本质是:
x=4*m,m是具体几倍,对7来讲,m就是2,对齐的结果就是8,而m具体是多少,取决于n是多少- 如果
n能整除4,那么m就是n/4 - 如果
n不能整除4,那么m就是n/4+1
- 如果
- 上面是两种情况,如何合并成为一种写法呢?
- 常见做法是
(n+sizeof(int)-1))/sizeof(int) -> (n+4-1)/4 - 如果
n能整除4- 那么
m就是(n+4-1)/4 -> (n+3)/4,+3的值无意义,会因取整自动消除,等价于n/4
- 那么
- 如果
n不能整除4- 那么n=最大能整除4部分+r,
1 <= r < 4 - 那么m就是(n+4-1)/4 --> (能整除4部分+r+3)/4,其中
4 <= r+3 < 7--> 能整除4部分/4 + (r+3)/4 -> n/4+1
- 那么n=最大能整除4部分+r,
- 常见做法是
- 既然是4的最小整数倍取整,那么本质是:
- 第二步理解:最小4字节对齐数
- 搞清楚了满足条件最小是几倍问题,那么,计算一个最小数字
x,满足x>=n && x%4==0,就变成了((n+sizeof(int)-1)/sizeof(int))[最小几倍] * sizeof(int)[单位大小] -> ((n+4-1)/4)*4 - 这样就能求出来4字节对齐的数据了,其实上面的写法,在功能上,已经和源代码中的宏等价了
- 搞清楚了满足条件最小是几倍问题,那么,计算一个最小数字
- 第三步理解:理解源代码中的宏
- 拿出简洁写法:
((n+4-1)/4)* 4,设w=n+4-1,那么表达式可以变化成为(w/4)*4,而4就是 2 2 2^2 22,w/4不就相当于右移两位吗?再次*4不就相当左移两位吗?先右移两位,在左移两位,最终结果就是,最后2个比特位被清空为0! - 需要这么费劲吗?
w & ~3不香吗?
- 所以,简洁版:
(n+4-1) & ~(4-1) - 原码版:
( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ),无需先/,再*
- 拿出简洁写法:
- 第一步理解:4的倍数
- 是什么?
- 前提:
- 图解

相关文章:
[C][可变参数列表]详细讲解
目录 1.宏含义及使用2.宏原理分析1.原理2.宏理解 1.宏含义及使用 依赖库stdarg.hva_list 其实就是char*类型,方便后续按照字节进行指针移动 va_start(arg, num) 使arg指向可变参数部分(num后面) va_arg(arg, int) 先让arg指向下个元素,然后使用相对位置…...
54. 螺旋矩阵【rust题解】
题目 给你一个 m 行 n 列的矩阵 matrix ,请按照 顺时针螺旋顺序 ,返回矩阵中的所有元素。 示例 示例 1 输入:matrix [[1,2,3],[4,5,6],[7,8,9]] 输出:[1,2,3,6,9,8,7,4,5] 示例 2 输入:matrix [[1,2,3,4],[5,6,…...
学习笔记——网络参考模型——TCP/IP模型(传输层)
四、TCP/IP模型-传输层 一、TCP 1、TCP定义 TCP(Transmission Control Protocol,传输控制协议)∶为应用程序提供可靠的面向连接的通信服务。目前,许多流行的应用程序都使用TCP。 连接:正式发送数据之前,提前建立好一种虚拟的&…...
Java中的Instant
在Java中,Instant 是 java.time 包中的一个类,用于表示时间轴上的一个瞬时点,通常以纳秒精度表示。它通常用于表示机器可读的时间戳,而不是人类可读的时间表示(如日期和时间)。 Instant 主要用于时间计算和…...
PostgreSQL的锁介绍
PostgreSQL的锁介绍 PostgreSQL 中的锁机制是一种用于控制数据并发访问的手段,确保数据库的完整性和一致性。在实际应用中,合理使用锁可以避免数据不一致和减少死锁的发生。 锁类型 PostgreSQL 提供了多种锁类型,以下是一些常见的锁&#…...
4分之1外螺纹怎么编程:挑战与策略解析
4分之1外螺纹怎么编程:挑战与策略解析 在机械制造领域,螺纹编程是一项至关重要的技术任务。当面对如4分之1外螺纹这样的具体需求时,编程人员需要综合运用专业知识与编程技巧,以确保螺纹的精确度和生产效率。本文将围绕四个方面、…...
运用selenium爬取京东商品数据储存到MySQL数据库中
使用Selenium爬取京东商品数据并存储到MySQL数据库中的过程可以分为几个步骤: 1. 准备工作 安装所需库 确保你已经安装了Python环境以及以下库: selenium:用于自动化浏览器操作。pymysql 或 mysql-connector-python:用于连接M…...
K8S SWCK SkyWalking全链路跟踪工具安装
官方参考:如何使用java探针注入器? 配置两个demo,建立调用关系, 首先创建一个基础镜像dockerfile from centos 先安装java 参考: linux rpm方式安装java JAVA_HOME/usr/java/jdk1.8.0-x64 CLASSPATH.:$JAVA_HOME/lib/tools.jar PATH…...
Apache Omid Idea Debug 环境搭建
IDEA 搭建 Apache Omid 源码 DEBUG 环境 Apache Omid 在 Apache HBase 之上提供了多行分布式事务的能力,支持全局 MVCC 功能。简单介绍编译过程。 1.下载 HBase2 并启动 https://dlcdn.apache.org/hbase/ 配置环境变量 export HBASE_HOME/xxx/hbase-2.4.18 exp…...
【面试宝藏】Go并发编程面试题
深入Go语言并发编程 Go语言以其简洁、高效的并发处理能力而闻名。在Go中,通过各种同步机制和原子操作,可以轻松地实现高性能并发编程。本文将深入探讨Go语言中的并发编程,包括Mutex、RWMutex、Cond、WaitGroup、原子操作等内容。 1. Mutex几…...
④单细胞学习-cellchat细胞间通讯
目录 1,原理基础 流程 受体配体概念 方法比较 计算原理 2,数据 3,代码运行 1,原理基础 原文学习Inference and analysis of cell-cell communication using CellChat - PMC (nih.gov) GitHub - sqjin/CellChat: R toolk…...
即时通讯平台及门户系统WorkPlus打造移动应用管理平台
在全球化和数字化时代,企业管理和沟通的方式正发生着巨大的变化。为了实现高效的协作和资源共享,企业越来越倾向于使用即时通讯及门户系统。这两种系统结合起来,可以提供一套完整的沟通和信息发布平台,促进内部协作和信息管理。 …...
React@16.x(12)ref 转发-forwardRef
目录 1,介绍2,类组件如何使用4,应用场景-高阶组件HOC 1,介绍 上篇文章中提到,ref 只能对类组件使用,不能对函数组件使用。 而 ref 转发可以对函数组件实现类似的功能。 使用举例: import Re…...
电脑世界的大冒险:用人体比喻让孩子轻松理解电脑20240603
电脑世界的大冒险:用人体比喻让孩子轻松理解电脑 作为一名在IT行业的老程序猿,我见证了电脑技术的飞速发展,也亲身体验了科技给生活带来的翻天覆地的变化。然而,在这个日新月异的数字时代,我意识到,与孩子…...
构建智慧银行保险系统的先进技术架构
随着科技的不断发展,智慧银行保险系统正日益受到关注。在这个数字化时代,构建一个先进的技术架构对于智慧银行保险系统至关重要。本文将探讨如何构建智慧银行保险系统的先进技术架构,以提升服务效率、降低风险并满足客户需求。 ### 1. 智慧银…...
来自大厂硬盘的降维打击!当希捷酷玩520 1TB SSD卷到369,请问阁下该怎么应对?
来自大厂硬盘的降维打击!当希捷酷玩520 1TB SSD卷到369,请问阁下该怎么应对? 哈喽小伙伴们好,我是Stark-C~ 今年4月份的时候因为电脑上的游戏盘突然挂掉,为了性价比选购了希捷酷玩520 1TB SSD,同时我也是…...
什么是封装?为什么是要封装?
封装是面向对象编程中的一种核心概念,它是将数据和操作数据的方法结合起来,形成一个整体,对外只暴露必要的接口,隐藏内部的具体实现细节。 封装的目的是为了实现信息隐藏和代码的模块化,具体原因如下: 1.…...
Spring Cloud | 服务 “注册与发现“ 框架 : Eureka框架
目录: Eureka 的 "工作机制" :一、Eureka 的 "工作原理" ( 两大组件 ) :1.1 Eureka Server ( 服务注册中心 )1.2 Eureka Client ( 服务/服务实例,其存在 "两种角色" : ①服务提供者 ②服务消费者 ) :Eureka Client 的 含义…...
编译链接问题
问题描述 C语言在编译的时候,提示链接的时候没有找到相应的方法 问题分析 代码文件结构: test.c test/1.c test/1.h test.c代码: #include “test/1.h” void main() { hello(); } test/1.c代码: void hello() { printf(“hel…...
电涡流的形成范围
电涡流的形成范围涉及多个方面,主要受到导体材料、磁场变化速度、导体形状和尺寸以及磁场方向的影响。以下是对这些因素的详细分析: 导体材料:金属和合金是最容易产生电涡流的材料,而非金属材料(如陶瓷、塑料等&#…...
【根据当天日期输出明天的日期(需对闰年做判定)。】2022-5-15
缘由根据当天日期输出明天的日期(需对闰年做判定)。日期类型结构体如下: struct data{ int year; int month; int day;};-编程语言-CSDN问答 struct mdata{ int year; int month; int day; }mdata; int 天数(int year, int month) {switch (month){case 1: case 3:…...
Flask RESTful 示例
目录 1. 环境准备2. 安装依赖3. 修改main.py4. 运行应用5. API使用示例获取所有任务获取单个任务创建新任务更新任务删除任务 中文乱码问题: 下面创建一个简单的Flask RESTful API示例。首先,我们需要创建环境,安装必要的依赖,然后…...
树莓派超全系列教程文档--(62)使用rpicam-app通过网络流式传输视频
使用rpicam-app通过网络流式传输视频 使用 rpicam-app 通过网络流式传输视频UDPTCPRTSPlibavGStreamerRTPlibcamerasrc GStreamer 元素 文章来源: http://raspberry.dns8844.cn/documentation 原文网址 使用 rpicam-app 通过网络流式传输视频 本节介绍来自 rpica…...
DeepSeek 赋能智慧能源:微电网优化调度的智能革新路径
目录 一、智慧能源微电网优化调度概述1.1 智慧能源微电网概念1.2 优化调度的重要性1.3 目前面临的挑战 二、DeepSeek 技术探秘2.1 DeepSeek 技术原理2.2 DeepSeek 独特优势2.3 DeepSeek 在 AI 领域地位 三、DeepSeek 在微电网优化调度中的应用剖析3.1 数据处理与分析3.2 预测与…...
系统设计 --- MongoDB亿级数据查询优化策略
系统设计 --- MongoDB亿级数据查询分表策略 背景Solution --- 分表 背景 使用audit log实现Audi Trail功能 Audit Trail范围: 六个月数据量: 每秒5-7条audi log,共计7千万 – 1亿条数据需要实现全文检索按照时间倒序因为license问题,不能使用ELK只能使用…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
相机Camera日志分析之三十一:高通Camx HAL十种流程基础分析关键字汇总(后续持续更新中)
【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:有对最普通的场景进行各个日志注释讲解,但相机场景太多,日志差异也巨大。后面将展示各种场景下的日志。 通过notepad++打开场景下的日志,通过下列分类关键字搜索,即可清晰的分析不同场景的相机运行流程差异…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
力扣-35.搜索插入位置
题目描述 给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 class Solution {public int searchInsert(int[] nums, …...
