这个函数怎么用???

priest2010 2010-01-26 05:57:28
这个函数在被调用的时候有时有3个参数,有时有4个、5个参数,这是怎么回事,怎么去分辨使用,还有这个函数的具体的作用是什么,请高手帮忙看看……
#define va_start(ap,v) ( __va_start(&ap, _ADDRESSOF(v), _SLOTSIZEOF(v), \
__builtin_alignof(v), _ADDRESSOF(v)) )
#define va_arg(ap,t) ( *(t *)__va_arg(&ap, _SLOTSIZEOF(t), \
_APALIGN(t,ap), (t *)0) )
#define va_end(ap) ( __va_end(&ap) )

bool CUSBCommunicator::SendCommand(BOOL bWaitResponse,BYTE nCmdId,BYTE nParamCount,...)
{
BYTE szCmdString[128],*pCmdString=szCmdString;

memset(pCmdString,'0',20);//定长命令
*pCmdString++=0x1b;
*pCmdString++=nCmdId;
*pCmdString++=0x30+nParamCount;//参数个数
va_list list=va_start(list,nParamCount);
for(int i=0;i<4;i++)
{
if(i<nParamCount)//16 进制数...
{
WORD param=va_arg(list,WORD);
sprintf((char *)pCmdString,"%04x",param);
}
pCmdString+=4;
*pCmdString='0';//由于sprintf在末尾添加了结束标志,需要修改为'0'
}
va_end(list);
*pCmdString++=0;
long nCmLength=pCmdString-szCmdString;
return SendCommand(szCmdString,nCmLength,bWaitResponse);
}
...全文
95 5 打赏 收藏 转发到动态 举报
写回复
用AI写文章
5 条回复
切换为时间正序
请发表友善的回复…
发表回复
priest2010 2010-02-23
  • 打赏
  • 举报
回复
谢谢各位高人!!!!!!!!
zoulie 2010-01-26
  • 打赏
  • 举报
回复
C调用约定是调用者负责清栈(调用者知道参数的个数),
所以支持不定参数的函数,同LS讲的
IcyPlayer 2010-01-26
  • 打赏
  • 举报
回复
C/C++语言有一个不同于其它语言的特性,即其支持可变参数,典型的函数如printf、scanf等可以接受数量不定的参数。如:

printf ( "I love you" );
printf ( "%d", a );
printf ( "%d,%d", a, b );

第一、二、三个printf分别接受1、2、3个参数,让我们看看printf函数的原型:

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

从函数原型可以看出,其除了接收一个固定的参数format以外,后面的参数用"…"表示。在C/C++语言中,"…"表示可以接受不定数量的参数,理论上来讲,可以是0或0以上的n个参数。

本文将对C/C++可变参数表的使用方法及C/C++支持可变参数表的深层机理进行探索。

可变参数表的用法

1、相关宏

标准C/C++包含头文件stdarg.h,该头文件中定义了如下三个宏:

void va_start ( va_list arg_ptr, prev_param ); /* ANSI version */
type va_arg ( va_list arg_ptr, type );
void va_end ( va_list arg_ptr );

在这些宏中,va就是variable argument(可变参数)的意思;arg_ptr是指向可变参数表的指针;prev_param则指可变参数表的前一个固定参数;type为可变参数的类型。va_list也是一个宏,其定义为typedef char * va_list,实质上是一char型指针。char型指针的特点是++、--操作对其作用的结果是增1和减1(因为sizeof(char)为1),与之不同的是int等其它类型指针的++、--操作对其作用的结果是增sizeof(type)或减sizeof(type),而且sizeof(type)大于1。

通过va_start宏我们可以取得可变参数表的首指针,这个宏的定义为:

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

显而易见,其含义为将最后那个固定参数的地址加上可变参数对其的偏移后赋值给ap,这样ap就是可变参数表的首地址。其中的_INTSIZEOF宏定义为:

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

va_arg宏的意思则指取出当前arg_ptr所指的可变参数并将ap指针指向下一可变参数,其原型为:

#define va_arg(list, mode) ((mode *)(list =\
(char *) ((((int)list + (__builtin_alignof(mode)<=4?3:7)) &\
(__builtin_alignof(mode)<=4?-4:-8))+sizeof(mode))))[-1]

对这个宏的具体含义我们将在后面深入讨论。

而va_end宏被用来结束可变参数的获取,其定义为:

#define va_end ( list )

可以看出,va_end ( list )实际上被定义为空,没有任何真实对应的代码,用于代码对称,与va_start对应;另外,它还可能发挥代码的"自注释"作用。所谓代码的"自注释",指的是代码能自己注释自己。

下面我们以具体的例子来说明以上三个宏的使用方法。

2、一个简单的例子

#include <stdarg.h>
/* 函数名:max
* 功能:返回n个整数中的最大值
* 参数:num:整数的个数 ...:num个输入的整数
* 返回值:求得的最大整数
*/
int max ( int num, ... )
{
int m = -0x7FFFFFFF; /* 32系统中最小的整数 */
va_list ap;
va_start ( ap, num );
for ( int i= 0; i< num; i++ )
{
int t = va_arg (ap, int);
if ( t > m )
{
m = t;
}
}
va_end (ap);
return m;
}
/* 主函数调用max */
int main ( int argc, char* argv[] )
{
int n = max ( 5, 5, 6 ,3 ,8 ,5); /* 求5个整数中的最大值 */
cout << n;
return 0;
}

函数max中首先定义了可变参数表指针ap,而后通过va_start ( ap, num )取得了参数表首地址(赋给了ap),其后的for循环则用来遍历可变参数表。这种遍历方式与我们在数据结构教材中经常看到的遍历方式是类似的。


函数max看起来简洁明了,但是实际上printf的实现却远比这复杂。max函数之所以看起来简单,是因为:

(1) max函数可变参数表的长度是已知的,通过num参数传入;

(2) max函数可变参数表中参数的类型是已知的,都为int型。

而printf函数则没有这么幸运。首先,printf函数可变参数的个数不能轻易的得到,而可变参数的类型也不是固定的,需由格式字符串进行识别(由%f、%d、%s等确定),因此则涉及到可变参数表的更复杂应用。
jingzhongrong 2010-01-26
  • 打赏
  • 举报
回复
函数参数个数不定,

bool CUSBCommunicator::SendCommand(BOOL bWaitResponse,BYTE nCmdId,BYTE nParamCount,...)
{
BYTE szCmdString[128],*pCmdString=szCmdString;

memset(pCmdString,'0',20);//定长命令
*pCmdString++=0x1b;
*pCmdString++=nCmdId;
*pCmdString++=0x30+nParamCount;//参数个数
va_list list=va_start(list,nParamCount); //获取第4个参数及其后的参数
for(int i=0;i <4;i++)
{
if(i <nParamCount)//16 进制数...
{
WORD param=va_arg(list,WORD); //依次获取参数,参数类型为WORD
sprintf((char *)pCmdString,"%04x",param);
}
pCmdString+=4;
*pCmdString='0';//由于sprintf在末尾添加了结束标志,需要修改为'0'
}
va_end(list);
*pCmdString++=0;
long nCmLength=pCmdString-szCmdString;
return SendCommand(szCmdString,nCmLength,bWaitResponse);
}
priest2010 2010-01-26
  • 打赏
  • 举报
回复
比如调用的情形:
SendCommand(TRUE,CUSBCommunicator::CMD_START_STEP,2,0+13*16,steps);

SendCommand(TRUE,CUSBCommunicator::CMD_END_STEP,0);
……%……
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

16,472

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • Web++
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧