va_list(可变参数函数的使用)

news/2025/3/13 4:14:09/

A_LIST 是在C语言中解决变参问题的一组宏,变参问题是指参数的个数不定,可以是传入一个参数也可以是多个;可变参数中的每个参数的类型可以不同,也可以相同;可变参数的每个参数并没有实际的名称与之相对应,用起来是很灵活。

va_list 用法示例:

#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
int add(int arg,...);
int main(int arg,char* args[])
{int rel = add(4,10,10,10,10);printf("结果为 %d \r\n",rel);return 0;
}
//操作系统只给我们定义了几个宏,包含:va_list va_start() va_arg() va_end()
//注意这里我们要做的操作就是判断参数的个数,然后进行不同的处理,这是用户需要做的
int add(int arg,...)
{int ret = 0;va_list list;va_start(list,arg);while(arg > 0){ret += va_arg(list,int);arg--;}va_end(list);return ret;
}

VA_LIST的用法: 
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针; 
(2)然后用VA_START宏初始化变量刚定义的VA_LIST变量; 
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数); 
(4)最后用VA_END宏结束可变参数的获取。

上面是va_list的具体用法,下面讲解一下va_list各个语句含义(如上示例黑体部分)和va_list的实现。

//可变参数是由宏实现的,但是由于硬件平台的不同,编译器的不同,宏的定义也不相同,下面是VC6.0中x86平台的定义 :typedef char * va_list;     /* TC中定义为void*  */#define _INTSIZEOF(n)    ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) /*为了满足需要内存对齐的系统*/#define va_start(ap,v)    ( ap = (va_list)&v + _INTSIZEOF(v) )     /*ap指向第一个变参的位置,即将第一个变参的地址赋予ap*/#define va_arg(ap,t)       ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )   /*获取变参的具体内容,t为变参的类型,如有多个参数,则通过移动ap的指针来获得变参的地址,从而获得内容*/#define va_end(ap) ( ap = (va_list)0 )   /*清空va_list,即结束变参的获取*/

va_list ap ; 定义一个va_list变量ap 
va_start(ap,v) ;执行ap = (va_list)&v + _INTSIZEOF(v),ap指向参数v之后的那个参数的地址,即 ap指向第一个可变参数在堆栈的地址。 
va_arg(ap,t) , ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )取出当前ap指针所指的值,并使ap指向下一个参数。 ap+= sizeof(t类型),让ap指向下一个参数的地址。然后返回ap-sizeof(t类型)的t类型指针,这正是第一个可变参数在堆栈里的地址。然后 用取得这个地址的内容。 
va_end(ap) ; 清空va_list ap。

使用VA_LIST应该注意的问题: 
(1)因为va_start, va_arg, va_end等定义成宏,所以它显得很愚蠢,可变参数的类型和个数完全在该函数中由程序代码控制,它并不能智能地识别不同参数的个数和类型. 也就是说,你想实现智能识别可变参数的话是要通过在自己的程序里作判断来实现的. 
(2)另外有一个问题,因为编译器对可变参数的函数的原型检查不够严格,对编程查错不利.不利于我们写出高质量的代码。 
(3)由于参数的地址用于VA_START宏,所以参数不能声明为寄存器变量,或作为函数或数组类型

好了,是时候表演真正的技术的,咱们去看看大神是如何使用可变参函数的(源代码参考libevent)

void
event_errx(int eval, const char *fmt, ...)
{va_list ap;va_start(ap, fmt);_warn_helper(_EVENT_LOG_ERR, NULL, fmt, ap);va_end(ap);event_exit(eval);
}
static void
_warn_helper(int severity, const char *errstr, const char *fmt, va_list ap)
{char buf[1024];size_t len;//如果不为null则进行字符串的拼接操作if (fmt != NULL)//字符串的拼接函数 参数分别为内存首地址,内存块的大小,要拼接的格式,和其后跟的参数evutil_vsnprintf(buf, sizeof(buf), fmt, ap);elsebuf[0] = '\0';if (errstr) {len = strlen(buf);//这里为什么减3呢,那是因为我们的格式上面有 :+ 空格 + \0//其实这一段我们可以不用做,因为怎么输出也不会超的if (len < sizeof(buf) - 3) {evutil_snprintf(buf + len, sizeof(buf) - len, ": %s", errstr);}}event_log(severity, buf);
}
OK!



http://www.ppmy.cn/news/222264.html

相关文章

va_list函数

va_list是用来处理可变参数的&#xff0c;下面看一个示例。 #include "stdarg.h" #include <stdio.h>int test(char* msg, ...);int main() {test("hello", "wolrd",1);return 0; }int test(char* msg, ...) {va_list vaList; //定义一个…

va_start 用法

可以参考&#xff1a;C 标准库 - <stdarg.h> 1. 在C中&#xff0c;当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表 void foo(...); void foo(parm_list,...);这种方式和我们以前认识的不大一样&#xff0c;但我们要记住这是C中一种传参的形式…

检测到“_CRT_STDIO_ISO_WIDE_SPECIFIERS”的不匹配项

libboost_thread-vc142-mt-x64-1_82.lib(thread.obj) : error LNK2038: 检测到“_CRT_STDIO_ISO_WIDE_SPECIFIERS”的不匹配项: 值“0”不匹配值“1”(AcadStr.obj 中) 1> 正在创建库 x64\Release\ArxDbg.lib 和对象 x64\Release\ArxDbg.exp : fatal error LNK1319: 检测到 …

va_list分析

typedef char* va_list INTSIZEOF 宏,获取类型占用的空间长度&#xff0c;最小占用长度为int的整数倍&#xff1a; #define _INTSIZEOF(n) ( (sizeof(n) sizeof(int) - 1) & ~(sizeof(int) - 1) ) VA_START宏&#xff0c;获取可变参数列表的第一个参数的地址&#xff08…

va_start和va_end使用详解

转载于&#xff1a;http://www.cnblogs.com/hanyonglu/archive/2011/05/07/2039916.html 本文主要介绍va_start和va_end的使用及原理。 在以前的一篇帖子Format MessageBox 详解中曾使用到va_start和va_end这两个宏&#xff0c;但对它们也只是泛泛的了解。 介绍这两个宏之前先…

va_list介绍

va_list是在C语言中解决变参问题的一组宏&#xff0c;变参问题是指参数的个数不定&#xff0c;可以是传入一个参数也可以是多个; 可变参数中的每个参数的类型可以不同,也可以相同; 可变参数的每个参数并没有实际的名称与之相对应&#xff0c;用起来是很灵活。 va_list表示可变…

使用VA助手如何快速添加注释(按doxygen注释规范)

原文首发于微信公众号「3D视觉工坊」&#xff1a;使用VA助手如何快速添加注释(按doxygen注释规范) 首先&#xff0c;关于VA助手的破解安装教程&#xff0c;请参考&#xff1a;VS2015 Visual Assist X 破解版安装教程 此处分享一下我在工程中使用VA助手进行快速注释的小技巧&am…

修改va0n的title

va01 va02 va03用于管理销售订单&#xff0c;他们的抬头是&#xff1a;Create Sales Order: Initial Screen。 本文介绍如何通过隐式增强修改它的title:&#xff08;恨透了csdn不能插入图片&#xff09; TCODE: VA01 SYSTEM->>STATUS 双击进入屏幕101 双击module cua…