- 概述
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦;即使采用C++,如果参数个数不能确定,也很难采用函数重载.对这种情况,有些人采用指针参数来解决问题.下面就c语言中处理不定参数数目的问题进行讨论. - 定义
大家先看几宏.
在VC++6.0的include有一个stdarg.h头文件,有如下几个宏定义:
#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 ) // 将指针置为无效
如果对以上几个宏定义不理解,可以略过,接这看后面的内容. - 参数在堆栈中分布,位置
在进程中,堆栈地址是从高到低分配的.当执行一个函数的时候,将参数列表入栈,压入堆栈的高地址部分,然后入栈函数的返回地址,接着入栈函数的执行代码,这个入栈过程,堆栈地址不断递减,一些黑客就是在堆栈中修改函数返回地址,执行自己的代码来达到执行自己插入的代码段的目的.
总之,函数在堆栈中的分布情况是:地址从高到低,依次是:函数参数列表,函数返回地址,函数执行代码段.
堆栈中,各个函数的分布情况是倒序的.即最后一个参数在列表中地址最高部分,第一个参数在列表地址的最低部分.参数在堆栈中的分布情况如下:
栈底 高地址
| .......
| 函数返回地址
| .......
| 函数最后一个参数
| ....
| 函数第一个可变参数 <--va_start后ap指向
| 函数最后一个固定参数
| 函数第一个固定参数
栈顶 低地址
va_arg()取得类型t的可变参数值, 先是让ap指向下一个参数:
ap += _INTSIZEOF(t),然后在减去_INTSIZEOF(t),使得表达式结果为ap之前的值,即当前需要得到的参数的地址,强制转换成指向此参数的
类型的指针,然后用*取值
示例代码
- 代码说明:
int int_size = _INTSIZEOF(int);得到int类型所占字节数
va_start(arg_ptr, i); 得到第一个可变参数地址,根据定义(va_list)&v得到起始参数的地址, 再加上_INTSIZEOF(v) ,就是其实参数下一个参数的地址,即第一个可变参数地址.
j=va_arg(arg_ptr, int); 得到第一个参参数的值,并且arg_ptr指针上移一个_INTSIZEOF(int),即指向下一个可变参数的地址.
va_end(arg_ptr);置空arg_ptr,即arg_ptr=0;
总结:读取可变参数的过程其实就是堆栈中,使用指针,遍历堆栈段中的参数列表,从低地址到高地址一个一个地把参数内容读出来的过程.
在编程中应该注意的问题和解决办法
虽然可以通过在堆栈中遍历参数列表来读出所有的可变参数,但是由于不知道可变参数有多少个,什么时候应该结束遍历,如果在堆栈中遍历太多,那么很可能读取一些无效的数据.
解决办法:a.可以在第一个起始参数中指定参数个数,那么就可以在循环还中读取所有的可变参数;b.定义一个结束标记,在调用函数的时候,在最后一个参数中传递这个标记,这样在遍历可变参数的时候,可以根据这个标记结束可变参数的遍历;
下面是一段示例代码:
虽然可以根据上面两个办法解决读取参数个数的问题,但是如果参数类型都是不定的,该怎么办,如果不知道参数的类型,即使读到了参数也没有办法进行处理.解决办法:可以自定义一些可能出现的参数类型,这样在可变参数列表中,可以可变参数列表中的那类型,然后根据类型,读取可变参数值,并进行准确地转换.传递参数的时候可以这样传递:参数数目,可变参数类型1,可变参数值1,可变参数类型2,可变参数值2,....
这里有一个陷阱需要避免:
va_arg宏的第2个参数不能被指定为char、short或者float类型。
因为char和short类型的参数会被转换为int类型,而float类型的参数会被转换为double类型 ……
例如,这样写肯定是不对的:
c = va_arg(ap,char);
因为我们无法传递一个char类型参数,如果传递了,它将会被自动转化为int类型。上面的式子应该写成:
c = va_arg(ap,int);
——《C陷阱与缺陷》p164
这里给出一个完整的例子:
相关推荐
王爽汇编语言综合研究-函数如何接收不定数量的参数
1、c语言如何传递参数编写这样一个程序试验void showchar(char a,int b);main(){ showchar(a,2);}void showchar(char a,int b){ *(char far *)(0xb8000000 + 160*10 + 80) = a; *(char far *)(0xb8000000
C++ 函数中的不定参数
.定义 所谓不定参数,指的就是在函数的定义中
GDI文字绘制和windows下opengl文字绘制小结
GDI绘制文字,要设置文字的属性,主要就是通过设置DC中的font对象来实现的。 font对象的创建可以由createfont()、createfontIndirect()来实现。 HFONT CreateFont( int nHeight, // height of font int nWidth, // average
函数的不定长参数
1、对于在定义函数时设置了参数的情况,如参数的量较少,还能一个个输入,就如函数笔记内的例子。但当我们需要输入大量的,或是数量不固定的参数时,就需要不定长参数的帮助 2、函数的不定长参数分为:不定长位置参数、不定长关键字参数 3、不定长位置参数:在定义函数时,在括号内输入 *args。其中星号必须输入,而args则是参数名,可以用其他字符替代,但更推荐不要改 def func(*args): ...
Verilog仿真时读取bin文件模拟输入数据流,将输出数据流写入bin文件
需要关注的是,一般会省略文件起始地址和读取长度,那么mem为多大,就会从文件中读取多大的数据出来填充mem。如果只需要读取一次文件,那么代码到此就结束了,但是如果还需要每一帧都读取该文件转换为数据流,则在循环里判断新的一帧信号是否到来,在新的一帧再次打开一次文件,从头开始读取数据。
(篇八)C语言在母串删子串、输入位置截取子串
文章目录一、字符串二、删除指定的字符三、从母串中截取子串四、输入位置截取子串 本篇主要介绍C语言字符串中的相关操作,然后分析两个C语言实例——在母串中指定删除子串、在母串中截取子串 一、字符串 了解C 语言的都知道,C语言中没有字符串类型,所以C语言是用字符串常量、字符指针、字符数组来表示字符串。这些字符串都是以 NULL、’\0’或者ASCII==0来结尾。说白了就是一个个字符组成一串有序序列,...
printf不定长参数原理
printf函数实现不定长参数原理
ECC椭圆曲线加解密原理详解(配图)
椭圆曲线加解密原理详解 本文主要参照:ECC椭圆曲线详解(有具体实例)[1] 前言: 椭圆曲线(ECC)加密原理跟RSA加解密原理比起来,可真是晦涩难懂。拜读了大神Kalafinaian文章“ECC椭圆曲线详解(有具体实例)”,终于看到了参透的曙光。 由于原文中有微小的瑕疵,也为了便于阅读起来更加流畅,我重新整理了一下这篇文章。 为什么使用椭圆曲线加密算法? RSA的解决分解整数问题需要亚指数...
不定长参数函数的实现
源码如下: int sum(int num, ...) { int *p = &num + 1; int ret = 0; while(num--) { printf("%d\n", num); ret += *p++; } return ret; } int main(int argc, char* argv[]) { printf("%d\n", sum
Codex本地部署指南:从环境配置到API集成实战
Codex作为OpenAI推出的代码生成模型,能够根据自然语言描述自动生成代码片段,大幅提升开发效率。这次我们重点分析Codex的本地部署方案、硬件门槛、接口调用方式和实际使用效果,帮助开发者判断是否值得投入时间部署。 从技术架构看,Codex基于GPT-3模型微调,专门针对代码生成任务优化。最新版本支持多种编程语言,包括Python、JavaScript、Java、C++等主流语言。对于国内开发者来说,最关心的是能否在本地环境稳定运行,以及是否需要特殊网络配置。 1. 核心能力速览 能力项 技术说明 模型
腾讯游戏安全组件运行异常的全面解决方案
在使用腾讯游戏时,玩家可能会遭遇游戏安全组件运行异常的问题,这不仅影响游戏的正常启动,还可能在游戏过程中引发一系列问题。本文将详细介绍解决腾讯游戏安全组件运行异常的几种方法,帮助玩家重拾游戏乐趣。腾讯游戏安全组件运行异常是一个复杂的问题,可能涉及服务设置、游戏更新、系统环境优化以及硬件与驱动检查等多个方面。最后,希望本文能帮助玩家顺利解决腾讯游戏安全组件运行异常的问题,让玩家能够无忧无虑地享受游戏带来的乐趣。首先,我们需要从系统的服务管理入手,检查与游戏安全组件相关的服务是否正常运行。
object-c 不定参数的遍历和原理
object-c接收任意类型的参数: /** * 接收String类型的多个参数 * @param firsParam 第一个参数 */ -(void)TestString:(NSString*)firsParam, ... { va_list list; va_start(list, firsParam); NSString* param; NSLog
熵编码(五)-CABAC(一) 基础篇
前两篇算术编码文章介绍了算术编码原理和步骤。本篇文章介绍CABAC,基于上下文自适应的二进制算术编码。本文对CABAC的基本原理进行了详细的介绍和分析,下篇文章将会对H264编码中的CABAC熵编码的实际应用进行介绍。
c++不定参数函数
不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而一般情况下重载函数也足以替换它。尽管如此,既然大家对它比较感兴趣,我就简单总结一下它的使用和需要注意的常见问题。 原理 刚学C语言的时候,一般人都会首先接触printf函数。通过这个函数,你可以打印不定个数的变量...
【立创EDA-PCB设计基础】4.模块化布局
本文对本专栏绘制的原理图进行模块化布局,首先进行预布局(将每个模块放一起),然后进行精细化布局(按照原理图来精细化布局)。
ssm框架搭建
这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载
C语言不定参数函数
文章目录C语言不定参数不定参数不定参数实现原理示例代码 C语言不定参数 众所周知,C语言不支持函数重载,支持函数重载的是C++。究其原因,C语言在编译函数之后,将"_函数名"存放到函数库,而C++在编译函数之后,将"_函数名_参数类型_参数类型"存放到函数库 但是,在查询fcntl函数时,却发现其函数原型有多个 int fcntl(int fd, int cmd); int fcntl(int fd, int cmd, long arg); int fcntl(int fd, int cmd, struct
efm32 入门.pdf
本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。
C/C++不定参数
在C++中,我们就可以使用template来定义一个可变模版参数,最终通过可变模版参数来解决问题,其实他也是运用的递归的原理,递归的去对每一个参数进行调用,我们在这儿定义一个空的xprintf的作用就在于最后递归调用过去为空时就会发生一些问题,所以我们在这儿就定义一个空的调用,调用到最后打印一个换行符就可以了。当然,上面这一段代码是针对于某个特定的类型来说的,如果我们需要打印的是字符串的话,就需要使用到我们的vasprintf函数。它的作用是初始化一个。类型的变量和可变参数的最后一个固定参数的地址。
蓝牙模块HM-10手册
蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。
IMSL CNL 7.0.0 (x86-64)Crack
IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件
不定参数函数
不定参数的应用 不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而一般情况下重载函数也足以替换它。尽管如此,既然大家对它比较感兴趣,我就简单总结一下它的使用和需要注意的常见问题。 原理 刚学C语言的时候,一般人都会首先接触printf函数。通过这个函数,你可以打印不定个
python函数不定参数_python函数不定长参数使用方法解析
python函数不定长参数使用方法解析这篇文章主要介绍了python函数不定长参数使用方法解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下pathon中的函数可以使用不定长参数,可以用参数*args接收单个出现的参数,接收后存成一个元组;用**kwargs接收以键值对形式出现的参数,接收后存丰一个字典.下面的小程序能说明这个问题代码如下:def...
C语言中不定参数函数的使用
由于在C语言中没有函数重载,解决不定数目函数参数问题变得比较麻烦。C语言中实现不定参数函数的问题是利用调用函数时使用的堆栈来解决。原理是通过堆栈读取可选参数的值,直到读取到所设定的结束标志为止。 下面程序的可选参数的结束标志设置为可选参数参数小于0。 在VC++6.0的include有一个stdarg.h头文件,有如下几个宏定义: #define _INTSIZEOF(n) (
C语言 深度探究具有不定参数的函数
C语言虽然不支持泛型编程(至少C98是这样的),但是C语言却支持不定参数的函数,这里我深究一下里面的原理,并且学会它的使用,自己简单实现一个简单的printf函数。 注:这里使用的IDE为 vs2022至于如何实现不定参数的函数呢?这里可以看一下标准库是如何定义的: 这里 ,显然就是我们传入格式字符串,后面 出现了 …,这个类型没见过,那它应该是实现可变参数的关键了。在C语言中… 三点就表示不定参数,这里我们又遇到了一个新的问题,传入了不定参数之后如何拿出不定参数?使用几个宏就完成这一个操作,没错就是宏。定
C、C++不定参数的使用
不定参数当年做为C/C++语言一个特长被很多人推崇,但是实际上这种技术并没有应用很多。除了格式化输出之外,我实在没看到多少应用。主要原因是这种技术比较麻烦,副作用也比较多,而一般情况下重载函数也足以替换它。尽管如此,既然大家对它比较感兴趣,我就简单总结一下它的使用和需要注意的常见问题。 原理 刚学C语言的时候,一般人都会首先接触printf函数。通过这个函数,你可以打印不定个数的变量到屏幕,如...
不定参函数的使用
C语言和c++风格不定参函数的相关讲解介绍
C语言和C++中不定参数解析
函数传参传几个呢?两个太少,三个太多,我传一坤个,不定参数来帮你
不定参数的函数实现方式
前言 不定参数的函数实现,在c/c++里面,主要依靠<stdarg.h>里面的va_list,va_start,va_end。掌握了这三个内容的应用,基本可以写出不定参数的函数了 举例 void fun(const char* format,...) { char buf[4 + 1] = {0}; strncpy_s(buf, "info", 5); va_list x...
不定参数函数的运用与实现
在论坛里看了“printf("%f",10/3); 答案是多少?”这篇帖子后,自己写了下小结!!望大家不吝赐教!!! 实现原理和理论依据: 函数参数传递的时候,参数是线性的存储在内存中的,因此,如果知道参数存放的起始位置和结束位置,和参数的类型,那么就可以得到需要的所有参数. 关于不定参数头文件stdarg.h中的几个宏定义(每一个颜色板块为一个宏定义及其解释):
3932



被折叠的 条评论
为什么被折叠?



