C语言可变参数函数取参方法

宏元编程——技术——变参宏 1,获取变参数宏的个数 #define TL_VARIADIC_SIZE(...) TL_CAT(TL_VARIADIC_SIZE_I(__VA_ARGS__, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1,),) #define TL_VARIADIC_SIZE_I(e0, e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, size, 阅读详情

熟悉C的人都知道,C语言支持可变参数函数(Variable Argument Functions),即参数的个数可以是不定个,在函数定义的时候用(...)表示,比如我们常用的printf()\execl函数等;printf函数的原型如下:

int printf(const char *format, ...);

注意,采用这种形式定义的可变参数函数,至少需要一个普通的形参,比如上面代码中的*format,后面的省略号是函数原型的一部分。

C语言之所以可以支持可变参数函数,一个重要的原因是C调用规范中规定C语言函数调用时,参数是从右向左压入栈的;这样一个函数实现的时候,就无需关心调用他的函数会传递几个参数过来,而只要关心自己用到几个;以printf为例:

printf("%d%s\n",i,s);

printf函数在定义的时候,不知道函数调用的时候会传递几个参数。在实现上,printf函数只需关心第一个参数,即字符串“%d%s\n”,当读到%d的时候,printf知道自己需要第二个参数,这时只需要去栈上寻找即可;当读到%s时,再去栈上网上寻找一个参数即可。简单说,printf不关心栈上到底压了多少参数,只关心自己需要多少。

那么对于一个定义为可变参数的函数,函数定义的时候并没有定义形参原型,怎么使用参数呢?

C语言定义了一系列宏来完成可变参数函数参数的读取和使用:宏va_start、va_arg和va_end;在ANSI C标准下,这些宏定义在stdarg.h中。三个宏的原型如下:

void va_start(va_list ap, last);//取第一个可变参数(如上述printf中的i)的指针给ap,last是函数声明中的最后一个固定参数(比如printf函数原型中的*fromat);

type va_arg(va_list ap, type);//返回当前ap指向的可变参数的值,然后ap指向下一个可变参数;type表示当前可变参数的类型(支持的类型位int和double);

void va_end(va_list ap);//将ap置为NULL

当一个函数被定义位可变参数函数时,其函数体内首先要定义一个va_list的结构体类型,这里沿用原型中的名字,ap。

va_start使ap指向第一个可选参数。va_arg返回参数列表中的当前参数并使ap指向参数列表中的下一个参数。va_end把ap指针清为NULL。函数体内可以多次遍历这些参数,但是都必须以va_start开始,并以va_end结尾。

下面是一个具体的示例(摘自wikipedia):

#include <stdarg.h>

 

double average(int count, ...)

{

    va_list ap;

    int j;

    double tot = 0;

    va_start(ap, count); //使va_list指向起始的參數

    for(j=0; j<count; j++)

        tot+=va_arg(ap, double); //檢索參數,必須按需要指定類型

    va_end(ap); //釋放va_list

    return tot/count;

}

除此之外,我们还需要注意一个陷阱,即va_arg宏的第2个参数不能被指定为char、short或者float类型。《C和C++经典著作:C陷阱与缺陷》在可变参数函数传递时,因为char和short类型的参数会被提升为int类型,而float类型的参数会被提升为double类型 。

例如,以下的代码是错误的

a = va_arg(ap,char);

因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:

a = va_arg(ap,int);

还需要注意的一个问题是,即时我们知道在某种体系结构下C语言函数的参数都压在栈上,我们也应该避免直接去栈上取想要的参数,因为这样会降低程序的灵活性和可移植性,并带来一些安全上潜在的危险。上述的三个宏,包括va_list,在不同的体系结构下会有不同的实现方法,比如va_list,有的系统上直接指向栈;而有的系统却将其实现为一个指针数组。

 


C语言可变参数函数 在C99标准之后,可以使用宏定义中的。 阅读详情

相关推荐

C语言的变参函数

C语言的变参函数 先提一个问题,什么是变参函数?简单的讲就是一个函数形参的个数不固定。比如我们天天用的printf()函数就是一个变参函数。像printf("%d",i)是两个参数,而printf("%d %d",i,j)是三个参数。那么如何用以及如何写变参函数了,那我们就要从stdrag.h谈起了。 stdrag.h头文件 c99标准的7.15章节讲到了stdrag.h这个头文件,详细内容可以参...

guoweilkd的博客 871

c/c++:提取可变参数宏__VA_ARGS__中偶数位置参数

考虑一个可变参数宏__VA_ARGS__中奇数位代表参数类型,偶数位代码参数名,想要提取__VA_ARGS__中所有的偶数位的参数名,该怎么实现呢? 利用上一篇博客《c/c++:计算可变参数宏 __VA_ARGS__ 的参数个数》的成果可以获取__VA_ARGS__中参数的个数。在这个基础上添加一系列宏定义就可以实现,下面是完整代码及测试用例, gcc下测试通过: // 计算 __VA_AR...

10km的专栏 2154

学习利用ce修改游戏生命参数

易语言代码 游戏的简陋界面 用ce查找存储这个1000即生命值的内存地址(得先附加到目标程序上,点击左上角那个电脑按钮) 看到有很多值为1000的,但哪个是生命值呢?真相只有一个 我们点击一下打我这个按钮,看下面的ce界面上地址为004A65C0处的值变了,所以这个就是我们要找的生命值 接下来我们对生命值进行修改,修改为99

zsd747289639的博客 5万+

c语言 宏 可变参数,可变参数宏【C语言】

C99开始允许宏有可变参数,用省略号表达一个到多个参数,用__VA_ARGS__来传递参数。如果要使用零个到多个参数,则应该用##__VA_ARGS__来传递参数。#include#include#define DEBUG(fmt, ...) fprintf (stderr, fmt, __VA_ARGS__)int process (int i1, int i2){int val;DEBUG ...

weixin_36280317的博客 539

发那科机器人弧焊指令实战:从Search指令到组掩码设置的完整避坑指南

本文详细解析了发那科机器人弧焊指令系统的实战应用,从Search指令的正确使用到组掩码设置的避坑技巧。通过实际案例和参数优化建议,帮助工程师提升焊接质量和生产效率,避免常见错误操作。特别针对T2模式示教难题和外部轴协调运动提供了专业解决方案。

weixin_29040367的博客 185

Memory SystemsCache, DRAM, Disk翻译学习DRAM部分(二)

DRAM 的发展史

qq_33473931的博客 995

c语言宏使用

C(和C++)中的宏(Macro)属于编译器预处理的范畴,属于编译期概念(而非运行期概念)。下面对常遇到的宏的使用问题做了简单总结。关于#和##在C语言的宏中,#的功能是将其后面的宏参数进行字符串化操作(Stringfication),简单说就是在对它所引用的宏变量通过替换后在其左右各加上一个双引号。比如下面代码中的宏:#define WARN_IF(EXP) /  do{ if (EX

凡人凡居 787

RK3588部署rtmpose模型

摘要: 本文详细介绍了在RK3588开发板上部署RTMPose模型的全流程。首先在Ubuntu环境中搭建MMCV框架,通过MMPose工具将PTH模型转换为ONNX格式。随后使用RKNN-Toolkit2将ONNX模型转换为RKNN格式,并完成开发板部署。关键步骤包括模型转换(PTH→ONNX→RKNN)、环境配置和推理验证,最终实现人体姿态估计功能。整个过程涉及MMPose、RKNN-Toolkit等工具链的使用,为边缘计算场景下的实时姿态分析提供了可行方案。

qq_44224801的博客 1219

关于c语言可变参数的取得

#define _vlst (char *) #define _intsize(n) ((sizeof(n)+sizeof(int)-1)&(~(sizeof(int)-1))) #define _vastart(ap,v) (ap=_vlst(&v)+_intsize(v)) #define _vaarg(ap,t) (*(...

erhisme的专栏 463

水文仿真软件:HEC-RAS (Hydrologic Engineering Center‘s River Analysis System)_(7).一维非稳态水力模型

自定义脚本是通过编程语言(如 Python)编写的一系列自动化任务,可以帮助用户更高效地处理数据和运行模型。编写脚本:使用 Python 或其他编程语言编写自定义脚本。集成脚本:将脚本集成到 HEC-RAS 中,实现自动化数据处理和模型运行。

kkchenjj的博客 932

基于SVD矩阵分解的用户购物篮预测分析实战

基于SVD矩阵分解的用户购物篮预测分析实战

360

c语言子函数形式参数作用,C语言可变参数函数取参方法

熟悉C的人都知道,C语言支持可变参数函数(Variable Argument Functions),即参数的个数可以是不定个,在函数定义的时候用(...)表示,比如我们常用的printf()\execl函数等;printf函数的原型如下:int printf(const char *format, ...);int printf(const char *format, ...);注意,采用这种形式...

weixin_42497762的博客 559

Qt代码-军用仿真系统基础框架

ui->mapClickLabel->setText(QString("地图点击:(%.1f, %.1f)米").arg(worldPos.x()).arg(worldPos.y()));emit simulationEvent(QString("添加实体: %1 (ID: %2)").arg(attr.name).arg(entity.id()));// 像素坐标→世界坐标(米)

寒寒豆豆软件公司的博客 168

C 语言的可变参数表函数的设计

首先在介绍可变参数表函数的设计之前,我们先来介绍一下最经典的可变参数表printf函数的实现原理。 一、printf函数的实现原理 在C/C++中,对函数参数的扫描是从后向前的。C/C++的函数参数是通过压入堆栈的方式来给函数传参数的(堆栈是一种先进后出的数据结构),最先压入的参数最后出来,在计算机的内存中,数据有2块,一块是堆,一块是栈(函数参数及局部变量在这里),而栈是从内存的高地址向低地

Hackbuteer1的专栏 2万+

基于 YOLOv26 的遥感图像目标检测系统:从原理到模型

本文介绍了基于YOLOv26的遥感图像目标检测系统。YOLOv26凭借端到端设计、轻量化架构和小目标优化能力,有效解决了遥感图像中多尺度目标、复杂背景、小目标检测等挑战。系统采用CSPDarknet骨干网络和FPN+PAN特征融合模块,通过MuSGD优化器和改进损失函数提升训练效果。文章详细阐述了数据预处理、模型训练流程和优化技巧,包括Tile推理和混合精度训练。系统支持多种部署方式,在CPU上推理速度提升43%,能实现高精度、实时性的遥感目标检测,适用于城市规划、农业监测等场景。

一键难忘的博客 568

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C语言可变参数详解

1.什么是可变参数 在C语言编程中有时会遇到一些参数可变的函数,例如printf()、scanf(),其函数原型为: int printf(const char* format,…) int scanf(const char *format,…) 就拿 printf 来说吧,它除了有一个参数 format 固定以外,后面的参数其个数和类型都是可变的,用三个点“…”作为参数占位符。 2.参数列表的构成 任何一个可变参数的函数都可以分为两部分:固定参数和可选参数。至少要有一个固定参数,其声明与普通函

C/C++、嵌入式开发、深度学习算法、模型部署与推理优化 7850

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C语言可变参数函数_初探

一、什么是可变参数函数 C语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function)。这种函数需要固定数量的强制参数,后面是数量可变的可选参数。 其中,强制参数必须至少一个,可选参数数量可变,类型可变,可选参数的数量由强制参数的值决定,或由用来定义可选参数列表的特殊值决定。 其实我们早就接触过可变参数函数了,C 语言中最常用的可变参数函数例子是 printf()和 s...

how的博客 8346

Probability and Statistics - 4th edition

Probability and Statistics - 4th edition

C语言变参函数和可变参数宏

在上面的教程中,我们学会了变参函数的定义和使用,基本套路就是使用 va_list 、 va_start 、 va_end 等宏,去解析那些可变参数列表我们找到这些参数的存储地址后,就可以对这些参数进行处理了:要么自己动手,自己处理;要么继续调用其它函来处理。i ++) {}可变参数宏的定义和使用。其实,C99 标准已经支持了这个特性,但是其它的编译器不太给力,对 C99 标准的支持。

sinat_31039061的博客 5889

C++可变参数函数

C++可变参数函数的三种实现方法:C风格实现,基于initializer_list,和基于模板。三种实现方法的比较和优缺点总结。

riskLoveHe的博客 4万+

C/C++ 变参函数

目前大部分主流编译器的最新版本均支持了C++11标准(官方名为ISO/IEC14882:2011)大部分的语法特性,其中比较难理解的新语法特性可能要属。

Doublelv 的博客专栏。 6364

【C语言】变参函数

返回值类型 函数名(固定参数, ...) {va_list 参数列表;// 定义一个 va_list 类型的变量,用于访问变参va_start(参数列表, 固定参数);// 初始化 va_list,指定最后一个固定参数// 使用 va_arg() 宏获取变参va_end(参数列表);// 清理 va_list。

猫猫的小茶馆 1098

【C语言】format属性 | 变参函数

在C语言中,变参函数并不强制要求声明format属性,但这取决于你的用途。如果你的变参函数是用来处理格式化字符串的,比如类似于printf这样的函数,那么使用format属性是非常推荐的,因为它可以帮助静态分析工具理解函数参数的预期用途,从而提高代码的安全性和可维护性。

weixin_46334900的博客 1430

C语言的那些小秘密之变参函数的实现

在学习C语言的过程中我们可能很少会去写变参函数,印象中大学老师好像也没有提及过,但我发现变参函数的实现很巧妙,所以还是特地在此分析下变参函数的实现原理。无需标准C的支持,我们自己写代码来实现。先来看看一个实现代码:#include #define va_li

bigloomy的专栏 1万+
上一篇: container_of和list_for_each_entry 及其相关函数的分析
下一篇: CPSR 和 SPSR
LinuxWorking
博客等级 码龄10年 24粉丝 32原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值