va_start、va_end、va_list的使用

http://www.cnblogs.com/rainduck/archive/2010/11/10/1873417.html

 1:当无法列出传递函数的所有实参的类型和数目时,可用省略号指定参数表
void foo(...);
void
foo(parm_list,...);

2:函数参数的传递原理
函数参数是以数据结构:栈的形式存取,从右至左入栈.

#include <iostream>

void fun(int a, ...)
{
    int *temp = &a;
    temp++;
    for (int i = 0; i < a; ++i) {
        cout << *temp << endl;
        temp++;
    }
}

int main() {
    int a = 1;
    int b = 2;
    int c = 3;
    int d = 4;
    fun(4, a, b, c, d);
    system("pause");
    return 0;
}

//Output::
//1
//2
//3
//4

3:获取省略号指定的参数
在函数体中声明一个va_list,然后用va_start函数来获取参数列表中的参数,使用完毕后调用va_end()结束。像这段代码:

TestFun(char* pszDest, int DestLen, const char* pszFormat, ...)
{
    va_list args;
    va_start(args, pszFormat);
    _vsnprintf(pszDest, DestLen, pszFormat, args);
    va_end(args);
}

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

1).

#include <stdio.h>
#include <string.h>
#include <stdarg.h>

int demo(char*, ...);

int main(void)
{
    demo("DEMO", "This", "is", "a", "demo!", "");
}

int demo(char* msg, ...)
{
    va_list argp;
    int argno = 0;
    char* para;
    va_start(argp, msg);
    while (1)
    {
        para = va_arg(argp,char*);
        if (strcmp(para, "") == 0)
            break;
        printf("Parameter #%d is: %s
", argno, para);
        argno++;
    }
    va_end(argp);
    return 0;
}

2).

#include <stdio.h>
#include <stdarg.h>

void simple_va_fun(int start, ...)
{
    va_list arg_ptr;
    int nArgValue = start;
    int nArgCount = 0;
    va_start(arg_ptr, start);
    do {
        ++nArgCount;
        printf("the %d th arg: %d
", nArgCount, nArgValue);
        //输出各参数的值
        nArgValue = va_arg(arg_ptr,int);
        //得到下一个可变参数的值
    } while (nArgValue != -1);

    return;
}

int main(int argc, char * argv[]) {
    simple_va_fun(100, -1);
    simple_va_fun(100, 200, -1);
    return 0;
}

3).

#include <stdio.h>
#include <stdlib.h>

//一个简单的类似于printf的实现,//参数必须都是int 类型
void myprintf(char* fmt, ...)
{
    char* pArg = NULL;        //等价于原来的va_list
    char c;
    pArg = (char*) &fmt;    //注意不要写成p = fmt!!因为这里要对参数取址,而不是取值
    pArg += sizeof(fmt);    //等价于原来的va_start
    do {
        c = *fmt;
        if (c != '%')
        {
            putchar(c);     //照原样输出字符
        }
        else
        {   //按格式字符输出数据
            switch (*++fmt)
            {
            case 'd':
                printf("%d", *((int*) pArg));
                break;
            case 'x':
                printf("%#x", *((int*) pArg));
                break;
            default:
                break;
            }
            pArg += sizeof(int);//等价于原来的va_arg
        }
        ++fmt;
    } while (*fmt != '');
    pArg = NULL; //等价于va_end
    return;
}

int main(int argc, char* argv[])
{
    int i = 1234;
    int j = 5678;

    myprintf("the first test:i=%d
", i, j);
    myprintf("the secend test:i=%d;%x;j=%d;
", i, 0xabcd, j);
    system("pause");
    return 0;
}

 还记得printf函数调用的时候那个“...”吗?就是可以输入任意的参数。现在你用va_list也可以实现类似的函数声明,printf就是这样做的。
 va_list args;                     //声明变量
 va_start(args,  before);          //开始解析。args指向before后面的参数
 参数类型 var = va_arg(args,  参数类型);//取下一个参数并返回。args指向下一个参数
 va_end(args);               //结束解析

原文地址:https://www.cnblogs.com/liulipeng/p/3443662.html