当前位置: 首页 > article >正文

C语言——变参函数

一、定义

        一般函数的参数列表是固定的,所以在调用时传入的实参的个数和格式必须和实参匹配;在函数式中,不需要关心实参,直接调用形参即可。

         变参函数,就是参数的个数及类型都不确定的函数,常见变参函数如printf、scanf。因为传入的参数列表是不确定的,所以在函数实现时要对传入的参数的个数以及类型进行判断乃至处理。

二、声明方式

        声明方式:返回值 函数名(第一个参数, ...);

        注:声明或定义变参函数时,第一个参数必须要有,其主要作用是明确到底有多少个参数,以及参数类型,后面的参数用“...”代替。

三、使用

3.1用指针的方式

        很多教材以及网上给出的示例代码:

void print_num(int count, ...)
{
    int *args;
    args = &count + 1;
    for( int i = 0; i < count; i++)
    {
        printf("*args: %d\n", *args);
        args++;
    }
}
int main(void)
{
    print_num(5,1,2,3,4,5);
    return 0;
}

        这是有问题的!

        运行结果:

         打印出来的结果是混乱的。

       函数实现思路是定义一个变参函数print_num,在函数内部先取得第一个参数的地址赋值给一指针,然后将指针后移,取得后面的参数并打印出来。

        错误原因:

       1.指针在64位系统中大小为8byte,示例代码中的“args++;”偏移的是一个int数据类型的大小,即4byte。

       2.第一个参数和第二个该参数之间的距离为28byte。通过“gcc -S 源文件”命令,生成后缀为“.s”的汇编代码文件,在汇编文件中找到的这个信息,具体原因我也还不知道。

         从上图可以看到在函数print_num中,第一个参数位置为196,第二个参数位置为168,二者之间相差28byte。从第二个参数开始,后续参数之间的距离为8byte。

        关于这个示例代码的错误,这篇文章很有参考价值:https://www.cnblogs.com/lularible/p/15129183.html

        正确代码:

void print_num(int count, ...)
{
    char *args;
    args = (char *)&count + 28;
    for( int i = 0; i < count; i++)
    {
        // printf("addr:%p\n",args);
        printf("*args: %d\n", *(int*)args);
        args+=8;
    }
}

        运行结果:

3.2用宏定义的方式

        头文件:#include <stdarg.h>
        头文件中定义的常用的宏:
        va_list:定义在编译器头文件中 typedef char* va_list; 
        void va_start(va_list ap, last);提取第一个参数last后面的第一个参数的地址,并赋值给va_list类型的指针变量ap;
        type va_arg(va_list ap, type); 返回下一个参数的地址,返回类型为type,每次执行时是返回的上一次返回的参数的下一个参数,而不是每次都是第二个参数;
        void va_end(va_list ap); 销毁va_list类型的指针变量ap,并将其赋值为空。

        函数实现:

void print_num(int count, ...)
{
    va_list arg;        //声明一个va_list类型的指针变量
    va_start(arg,count);//初始化指针变量arg为count的下一个参数的地址
    int temp;
    for(int i=0;i<count;i++)
    {
        temp = va_arg(arg,int);         //返回后续的参数
        printf("*args: %d\n", temp);
    }
    va_end(arg);    //销毁这个指针变量
}

        关于使用宏来做变参函数,这篇博客具有很好的参考价值,但使用指针实现部分也是有一点问题的。https://blog.csdn.net/sinat_31039061/article/details/128338331


http://www.kler.cn/news/9816.html

相关文章:

  • 为什么Java8不使用CMS作为默认垃圾收集器
  • 死锁的检测和案例
  • Qt使用std::thread更新QPlainTextEdit内容
  • 透过Gartner最新报告,认识“超级边缘”
  • Java 包详细讲解
  • ChatGPT想干掉开发人员,做梦去吧
  • ERTEC200P-2 PROFINET设备完全开发手册(4-2)
  • 4.9--计算机网络之TCP篇之TCP 重传、滑动窗口、流量控制、拥塞控制--(复习+大总结)---好好沉淀,沉下心来
  • 真题详解(Flynn分类)-软件设计(四十六)
  • 【Linux】线程概念详析
  • 博客平台用户模块设计原则:构建简洁、高效的用户体验
  • 100种思维模型之非共识思维模型-48
  • 板块模型构建、k点选定及Miller指数对表面分类
  • 代码随想录算法训练营第五十二天 | 300.最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组
  • 液压传动与控制实验教学培训系统平台
  • Bootloader的作用
  • [ 应急响应基础篇 ] Windows系统隐藏账户详解(Windows留后门账号)
  • 从存算分离说起:金融行业数据库分布式改造之路
  • 【Linux】工具(5)——gdb
  • 浏览器:好用的浏览器插件,亲测好用