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

来源:互联网 发布:网络与新媒体概论 pdf 编辑:程序博客网 时间:2024/05/01 02:49
 

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

分类: C&C++ 372人阅读 评论(0) 收藏 举报

        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作为可变参数列表的终结。

[cpp] view plaincopyprint?
  1. void nstrcat(char *dest, ...){  
  2.     va_list     ap;   
  3.     char        *p, *q;   
  4.   
  5.     va_start(ap, dest);  
  6.     while( (p = va_arg(ap, char *)) != NULL ){  
  7.         strcat(dest, p);   
  8.         dest += strlen(p);  
  9.     }     
  10.           
  11.     va_end(ap);  
  12. }  
  13.   
  14. void nstrcpy(char *dest, ...){  
  15.     va_list     ap;   
  16.     char        *p;   
  17.   
  18.     va_start(ap, dest);  
  19.     while( (p = va_arg(ap, char *)) != NULL){  
  20.         strcpy(dest, p);  
  21.         dest += strlen(p);  
  22.     }  
  23.   
  24.     va_end(ap);  
  25. }  
        运行测试一下:

[cpp] view plaincopyprint?
  1. int  
  2. main(int argc, char** argv){  
  3.     char    buf[1000], bufa[100];  
  4.     char    a[] = "abc,123";  
  5.     char    b[] = "456";  
  6.     char    c[] = "090";  
  7.   
  8.     nstrcpy(buf, a, b, c, NULL);  
  9.   
  10.     strcpy(bufa, "nbakk__");  
  11.     nstrcat(bufa, b, "__", a, "__", c, NULL);  
  12.   
  13.     printf("nstrcpy: %s\n", buf);  
  14.     printf("nstrcat: %s\n", bufa);  
  15. }  
        通过这两个函数可以很方便的实现多个字符串的操作,程序的输出是:

[plain] view plaincopyprint?
  1. nstrcpy: abc,123456090  
  2. 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)个字节,这样去遍历可变参数。这是我对于可变参数的实现的理解和猜测,不一定对啊。。。

原创粉丝点击