C语言可变参数列表应用——多字符串复制和链接

        C标准库中<stdarg.h>头文件中包含可变参数列表的实现,完成遍历未知数目和类型的函数参数列表的功能。提供以下3个宏以及va_list变量:

                va_start(va_list ap, lastarg):在提取可变参数前必须调用这个宏实现初始化。

                va_arg(va_list ap, type_of_var):用于提取变量,type_of_var是提取的变量的类型。返回对应类型的参数。

                va_end(va_list ap):在参数处理完毕之后,必须调用va_end做一些清理。

        通过这3个宏就可以实现可变参数的遍历,下面看一下多字符的复制和链接的实现,这两个函数都是通过NULL作为可变参数列表的终结。

void nstrcat(char *dest, ...){
    va_list     ap; 
    char        *p, *q; 

    va_start(ap, dest);
    while( (p = va_arg(ap, char *)) != NULL ){
        strcat(dest, p); 
        dest += strlen(p);
    }   
        
    va_end(ap);
}

void nstrcpy(char *dest, ...){
    va_list     ap; 
    char        *p; 

    va_start(ap, dest);
    while( (p = va_arg(ap, char *)) != NULL){
        strcpy(dest, p);
        dest += strlen(p);
    }

    va_end(ap);
}
        运行测试一下:

int
main(int argc, char** argv){
    char    buf[1000], bufa[100];
    char    a[] = "abc,123";
    char    b[] = "456";
    char    c[] = "090";

    nstrcpy(buf, a, b, c, NULL);

    strcpy(bufa, "nbakk__");
    nstrcat(bufa, b, "__", a, "__", c, NULL);

    printf("nstrcpy: %s\n", buf);
    printf("nstrcat: %s\n", bufa);
}
        通过这两个函数可以很方便的实现多个字符串的操作,程序的输出是:

nstrcpy: abc,123456090
nstrcat: nbakk__456__abc,123__090
        下面看一下可变参数(Variable Arguments)的实现原理,比如我们调用一个传入多个int型可变参数的函数,比如avg(int a, ...)。

                   |--------------|

                   |        23      |       最后一个可变参数

                   |--------------|       0x10000008

                   |        12      |       第一个可变参数

                   |--------------|       0x10000004

                   |         1       |       最后一个固定参数

     %ebp--> |--------------|       0x10000000

                   |                   |

                   |--------------|

                       ............

                   |--------------|

                   |                   |

    %esp-->  |---------------|

        CPU的%ebp是帧指针,%esp是栈指针,在%ebp和%esp之间的内存就是当前函数的栈帧,传给当前函数的实参是在调用函数的栈帧中,顺序放置在%ebp后面。比如上图就是调用avg(1, 12, 23)的栈对应的状态。根据栈的状态,a对应的是1,a的起始地址是0x10000000,va_list变量实际就是char *,当调用va_list(ap, a)后,ap对应的就是0x10000004。当调用int n = va_arg(ap, int),相当于执行(*(int *)ap)也就是12,然后将ap += sizeof(int),这时ap指向0x10000008,也就是根据传入va_arg的类型type,跳过sizeof(type)个字节,这样去遍历可变参数。这是我对于可变参数的实现的理解和猜测,不一定对啊。。。


你可能感兴趣的:(C语言可变参数列表应用——多字符串复制和链接)