Linux 下 va_start、va_end 学习及使用

本文详细介绍了可变参数函数的实现方法,包括va_start、va_arg、va_end和va_copy等函数的用法,并提供了多个示例代码帮助理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文主要介绍可变参数 函数的实现方法。

头文件:#include <stdarg.h>

一、函数系列介绍
1、va_start函数
原型:void va_start(va_list ap, last);
ap:va_list 类型的变量,指向参数的指针
last:最后一个显式声明的参数,以用来获取第一个变长参数的位置
2、va_arg函数
原型:type va_arg(va_list ap, type);
ap:va_list 类型的变量,指向参数的指针
type:指要获取的参数的类型
3、va_end函数
原型:void va_end(va_list ap);
ap:va_list 类型的变量,指向参数的指针
4、va_copy函数
原型:void va_copy(va_list dest, va_list src);

二、函数详细介绍

typedef char *  va_list;
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define ADDRESSOF(v)   ( &reinterpret_cast<const char &>(v) )

#define va_start _crt_va_start
#define va_arg _crt_va_arg
#define va_end _crt_va_end

#define _crt_va_start(ap,v)  ( ap = (va_list)_ADDRESSOF(v) + _INTSIZEOF(v) )
#define _crt_va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define _crt_va_end(ap)      ( ap = (va_list)0 )

三、使用步骤介绍
1)定义一个va_list类型的变量,变量是指向参数的指针;
2)va_start初始化刚定义的变量,第二个参数是最后一个显式声明的参数;
3)va_arg返回变长参数的值,第二个参数是该变长参数的类型;
4)va_end将a)定义的变量重置为NULL。

四、示例
示例1:

void test_printf2(int num,...)
{
    va_list args;
    int i = 0;
    va_start(args,num);
    for(i; i < num; i++)
        printf("%d\n", va_arg(args, int));
    va_end(args);
}
test_printf2(3,1,2,3);

示例2:

void test_printf6(char *headData, char *format,...)
{
    char buff[4096];
    va_list args;

    memcpy(buff, headData, strlen(headData));
    va_start(args, format);
    vsnprintf(buff+strlen(headData), 1024, format, args);
    va_end(args);

    printf("%s\n", buff);
}

test_printf6("requestData", "len is %d, data is %s", 10, "helloworld");

示例3:

void test_printf7(char *format,...)
{
    int tmpLen; 
    char *buff, *buf, *ptr;
    va_list args;

    buff = (char *) malloc(sizeof(char)*1024);
    buf = buff; 
    va_start(args, format);
    for (ptr = format; *ptr; ptr++) {
        if(*ptr == '%') {
            switch (*(++ptr)) {
                case 'd': 
                *buff++ = va_arg(args, int) + 0x30;
                break;
                case 's':
                tmpLen = va_arg(args, int); 
                memcpy(buff, va_arg(args, char *), tmpLen);
                buff += tmpLen;
                break;
                case 'c': 
                *buff++ = va_arg(args, int);
                break;
            }
        } else{
            printf("%c\n", *ptr);
        }
    }   
    *buff = '\0';
    printf("%s\n", buf);//此处需注意打印要从头指针开始
    va_end(args);
    free(buf);//此处需注意释放的是头指针,否则会出现下面的错误
    buf = NULL;
}

test_printf7("%d%d%s%c", 1,2,4,"helloWorld", 'E');

*** Error in `./a.out’: munmap_chunk(): invalid pointer: 0x0000000000e00047 ***
======= Backtrace: =========
/lib/x86_64-linux-gnu/libc.so.6(+0x77725)[0x7f982c4fa725]
/lib/x86_64-linux-gnu/libc.so.6(cfree+0x1a8)[0x7f982c506c18]
./a.out[0x401575]
./a.out[0x4015c8]
/lib/x86_64-linux-gnu/libc.so.6(__libc_start_main+0xf0)[0x7f982c4a3830]
./a.out[0x4006d9]
======= Memory map: ========
00400000-00402000 r-xp 00000000 08:01 919832 /home/zx/test/a.out
00601000-00602000 r–p 00001000 08:01 919832 /home/zx/test/a.out
00602000-00603000 rw-p 00002000 08:01 919832 /home/zx/test/a.out
00e00000-00e21000 rw-p 00000000 00:00 0 [heap]
7f982c26d000-7f982c283000 r-xp 00000000 08:01 792176 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f982c283000-7f982c482000 —p 00016000 08:01 792176 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f982c482000-7f982c483000 rw-p 00015000 08:01 792176 /lib/x86_64-linux-gnu/libgcc_s.so.1
7f982c483000-7f982c643000 r-xp 00000000 08:01 792138 /lib/x86_64-linux-gnu/libc-2.23.so
7f982c643000-7f982c842000 —p 001c0000 08:01 792138 /lib/x86_64-linux-gnu/libc-2.23.so
7f982c842000-7f982c846000 r–p 001bf000 08:01 792138 /lib/x86_64-linux-gnu/libc-2.23.so
7f982c846000-7f982c848000 rw-p 001c3000 08:01 792138 /lib/x86_64-linux-gnu/libc-2.23.so
7f982c848000-7f982c84c000 rw-p 00000000 00:00 0
7f982c84c000-7f982c872000 r-xp 00000000 08:01 792110 /lib/x86_64-linux-gnu/ld-2.23.so
7f982ca56000-7f982ca59000 rw-p 00000000 00:00 0
7f982ca6e000-7f982ca71000 rw-p 00000000 00:00 0
7f982ca71000-7f982ca72000 r–p 00025000 08:01 792110 /lib/x86_64-linux-gnu/ld-2.23.so
7f982ca72000-7f982ca73000 rw-p 00026000 08:01 792110 /lib/x86_64-linux-gnu/ld-2.23.so
7f982ca73000-7f982ca74000 rw-p 00000000 00:00 0
7ffe93f65000-7ffe93f86000 rw-p 00000000 00:00 0 [stack]
7ffe93ff0000-7ffe93ff2000 r–p 00000000 00:00 0 [vvar]
7ffe93ff2000-7ffe93ff4000 r-xp 00000000 00:00 0 [vdso]
ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
Aborted (core dumped)

示例4:

void test_printf5(char *data, char *format,...)
{
    char buff[1024];
    char *tmpBuff, *ptr;
    va_list args;
    int tmpLen = 0;

    tmpBuff = buff; 
    memset(tmpBuff, 0x00, sizeof(buff));
    memcpy(tmpBuff, data, strlen(data));
    tmpBuff += strlen(data);
    va_start(args, format); 
    for(ptr = format; *ptr; ptr++) {
        switch (*ptr) {
            case 'd':
                *tmpBuff++ = va_arg(args, int) + 0x30;
                break;   
            case 's':    
                tmpLen = va_arg(args, int);
                *tmpBuff++ = tmpLen + 0x30;
                memcpy(tmpBuff, va_arg(args, char *), tmpLen);
                tmpBuff += tmpLen;
                break;
            case 'c':
                *tmpBuff++ = va_arg(args, int);
                break;
        }
    } 
    va_end(args);
    *tmpBuff = '\0';    
    printf("%s\n", buff);
    return ;
}

test_printf5("reqeustData", "dcdsdsc",2,'A',3,4,"buffer",5,3,"heloo",'C');
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值