可变参数列表

来源:互联网 发布:java平台是什么 编辑:程序博客网 时间:2024/04/29 18:30

在函数原型中,列出了函数期望接受的参数,但原型只能显示固定数目的参数。让一个函数在不同的时候接受不同数目的参数是不是可以呢?答案是肯定的,但存在一些限制。

#include<stdio.h>#include<stdlib.h>#include<stdarg.h>//利用可变参数列表实现加法。int add(int num, ...){    int i = 0;    int sum = 0;    int tmp = 0;    va_list arg;//在这定义了一个char 类型的指针。    va_start(arg, num);//这个的功能是读取所有的参数,从头开始                      //后读取你所给的参数个数,并且把参数放到指针中。    for (i = 0; i < num; i++)    {        tmp = va_arg(arg, int);//在这,起到的作用是读取所给的参数        sum += tmp;    }    va_end(arg);//结束读取    return sum;}int main(){    int ret = 0;    ret=add(4,5,6,7,5);    printf("%d", ret);    system("pause");    return 0;}

这里写图片描述

要记住下面这些都封装在stdarg.h头文件中。
va_list arg这个说的就是一个char 类型的指针,并且记住地址
va_start(arg,…之前的一个参数) 读取所有的参数,从头开始后读取你所给的参数个数,并且把参数放到指针中。
va_arg (arg,类型)读取参数,挨个读取,返回这个参数的值,并且使得指向下一个可变参数。
va_end(arg) 结束读取。

*C语言中对可变参数的限制

-无法确定可变参数列表的长度。
-不能提供类型检查。

对于关键的宏进行解读

  • 1.va_list
    宏:#define _INTSIZEOF(n) ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
    这个宏本身只是个定义,真正赋予其意义的在于下面的几个宏。
    实现:实际上只是一个 char * 类型的指针,原因这里不能判定类型,所以用size为1的char类型指针会方便移动。

  • 2.va_start
    宏:#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
    这个宏需要两个参数,第一个是上面定义的 va_list, 第二个是可变参数列表之前的那个参数。
    注意:va_start中的参数,一定要是最后一个参数,也就是…之前的那个参数,不然可能会有问题。尤其是windows和linux的函数参数入栈顺序不同,会有可移植性问题。

  • 3.va_arg
    宏:#define va_arg(ap,t) ( (t )((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
    同样有两个参数,第一个是前面已经初始化好的 va_list,第二个是类型,比如这里可变参数列表的第一个参数是int类型,那么就传int。

  • 4.va_end
    宏:#define va_end(ap) ( ap = (va_list)0 )
    为了更好的可读性,结束可变参数的获取。

可变参数必须从头到尾按照顺序逐个进行访问,如果你在访问几个可变参数后想半途中止,这是可以的,但是不能一开始就访问参数列表中间的参数。

另外需要注意的是,参数列表中至少需要有一个命名参数。命名参数指定了实际传递的参数数量,
接下来,来用可变参数列表实现一个超级厉害的system函数。

#include<stdio.h>#include<stdlib.h>#include<stdarg.h>#include<string.h>void go(int num, ...){    int i = 0;    va_list arg;    va_start(arg, num);    for (i = 0; i < num; i++)    {        char arr[20];        strcpy(arr, va_arg(arg, char *));        printf("%s", arr);        system(arr);    }    va_end(arg);}int main(){    go(9,"notepad","calc","tasklist","ipconfig","mspaint","write","title wuyuzhe","color 3e","pause");}

这里写图片描述
这里写图片描述
这里写图片描述

在这里通过这个超级厉害的system函数可以实现打开记事本,计算器,查看进程,查询ip,画图工具,写字本,然后让命令行程序的标题改成了wuyuzhe,还改了颜色,然后最后执行了暂停。
很好很强大的东西,可以实现很多的指令。

接下来,我们用可变参数列表,实现一个部分printf()函数的功能
print(“s ccc.\n”,”hello”,’b’,’i’,’t’);
print(char *format, …)

#include<stdio.h>#include<stdlib.h>#include<stdarg.h>void print(char *format, ...){    va_list arg;    va_start(arg, format);    while (*format)    {        switch (*format)        {            case 'c':            {                char tmp = va_arg(arg, char);                putchar(tmp);            }                break;            case 's':            {                        char *str = va_arg(arg, char*);                        while (*str)                        {                            putchar(*str);                            str++;                        }            }                break;            default:                putchar(*format);                break;        }        format++;    }    va_end(arg);}int main(){    print("s ccc.\n", "hello", 'b', 'i', 't');    system("pause");    return 0;}
1 0