C语言中不定参数 ... 的语法、函数封装

news2024/11/14 20:49:22

文章目录

    • Intro
    • 语法测试
      • 依赖库
      • 新函数使用测试:遍历并打印不定参数中的值
      • 用两种方式封装函数:对多个int值求和
    • 总结

Intro

有一天看C代码看到某个方法有这样的定义:在函数形参列表处,有...的写法,就像Java中的不定参数那样。
如:

int	 printf(const char * __restrict, ...) __printflike(1, 2);
int	 scanf(const char * __restrict, ...) __scanflike(1, 2);

在这里插入图片描述
那么C语言中的不定参数特性,是怎样使用的呢,以及我们如何利用该特性,封装自己的函数?

语法测试

依赖库

需要用到 stdarg.h 中的三个函数:

#define va_start(ap, param) __builtin_va_start(ap, param)
#define va_end(ap)          __builtin_va_end(ap)
#define va_arg(ap, type)    __builtin_va_arg(ap, type)

在这里插入图片描述

新函数使用测试:遍历并打印不定参数中的值

主要是测试一下上面提到的三个库函数的使用。

#include <stdio.h>
#include <stdarg.h>

// 声明列表的结束值
#define ARGUMENTS_END_VALUE -1

void printMultiArgs(int firstArgs, ...) {

    // 声明参数列表的变量
    va_list ap;
    
    // 初始化参数列表
    va_start(ap, firstArgs);
    printf("%d\n", firstArgs);
    
    int currValue;
    while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
        printf("%d\n", currValue);
    }

    // 结束参数列表
    va_end(ap);
}

int main(int argc, const char * argv[]) {
    printMultiArgs(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE);
    return 0;
}

用两种方式封装函数:对多个int值求和

//
//  main.c
//  C不定参数
//
//  Created by wuyujin1997 on 2023/1/23.
//

//#define va_start(ap, param) __builtin_va_start(ap, param)
//#define va_end(ap)          __builtin_va_end(ap)
//#define va_arg(ap, type)    __builtin_va_arg(ap, type)

#include <stdio.h>
#include <stdarg.h>

// 声明列表的结束值
#define ARGUMENTS_END_VALUE -1

void printMultiArgs(int firstArgs, ...) {

    // 声明参数列表的变量
    va_list ap;
    // 初始化参数列表
    va_start(ap, firstArgs);
    printf("%d\n", firstArgs);
    
    int currValue;
    while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
        printf("%d\n", currValue);
    }

    // 结束参数列表
    va_end(ap);
}


/// 对多个int变量求和(需要提前约定好参数结束的标志值 ARGUMENTS_END_VALUE)
/// - Parameter firstArgs: <#firstArgs description#>
int sum1(int firstArgs, ...) {
    int result = 0;
    
    va_list ap;
    va_start(ap, firstArgs);
    result+= firstArgs; // 手动处理第一个参数
    int currValue;
    while ((currValue = va_arg(ap, int)) != ARGUMENTS_END_VALUE) {
        result += currValue;
    }
    va_end(ap);
    
    return result;
}


/// 对多个int变量求和(需要主动本方法:不定参数的个数是多少)
/// - Parameters:
///   - count: 不定参数的个数
///   - firstArgs: 第一个参数,显式的形参
int sum2(int count, int firstArgs, ...) {
    int result = 0;
    
    va_list ap;
    va_start(ap, firstArgs);
    result += firstArgs;
    for (int i = 1; i < count; i++) {
        int currValue = va_arg(ap, int);
//        printf("%d  %d\n", i, currValue);
        result += currValue;
    }
    va_end(ap);
    
    return result;
}

int main(int argc, const char * argv[]) {

    printMultiArgs(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE);
    printf("sum1  %d\n", sum1(1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE));
    int LENGTH = 9;
    printf("sum2  %d\n", sum2(LENGTH, 1,2,3,4,5,6,7,8,9, ARGUMENTS_END_VALUE));

    return 0;
}

执行结果:
在这里插入图片描述

总结

  • 需要引入头文件 #include <stdarg.h>
  • 一个新类型,三个新函数
    • 类型 va_list
    • 函数,其中 apva_list 类型的变量。
      • va_start(ap, param) param为不定参数列表的第一个参数。
      • va_arg(ap, type) 不定参数中变量的类型吗,如int, short, long 等。
      • va_end(ap)
  • 如何确定 va_arg 的size/有多少个元素? 没有原生的属性/变量可以告诉我们。
    • 约定一个值作为 end_value ,而且要保证:这个值不会出现在传入的多个参数值中。
    • 在咱自己封装的函数中,新增一个参数用于告知被调函数内部:本次不定参数的size是多少。
  • 注意不定参数的类型匹配。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176514.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

JDK8 新特性之Stream流方法详解

目录 一&#xff1a;集合处理数据的弊端 二&#xff1a;Stream流式思想概述 小结 &#xff1a; 三&#xff1a;获取Stream流的两种方式 方式1 : 根据Collection获取流 方式2 : Stream中的静态方法of获取流 小结 四&#xff1a;Stream常用方法和注意事项 Stream常用方法…

19. 函数基础知识详解

1. 什么是函数 函数是组织好的&#xff0c;可重复使用的&#xff0c;用来实现单一&#xff0c;或相关联功能的代码段。函数能提高应用的模块性&#xff0c;和代码的重复利用率。之前文章中我们已经使用过python提供的内建函数&#xff0c;比如print()。但你也可以自己创建函数…

【JUC并发编程】线程池及相关面试题 详解

【JUC并发编程】线程池及相关面试题 详解 参考资料&#xff1a; 第十二章 线程池原理 深入浅出Java多线程原理 两道面试题&#xff0c;深入线程池&#xff0c;连环17问 深入理解Java并发编程之线程池、工作原理、复用原理及源码分析 硬核干货&#xff1a;4W字从源码上分析JUC…

Java二叉树OJ题

目录1. 检查两颗树是否相同2. 另一颗树的子树3. 翻转二叉树4. 判断一颗二叉树是否是平衡二叉树4.1 时间复杂度为O(n*n)【从上而下递归】4.2 时间复杂度为O(n)【从下而上递归】5. 对称二叉树6. 二叉树的构建及遍历7. 二叉树创建字符串8. 两个指定节点的最近公共祖先8.1 指定结点…

java入门作业-DAO,读取sql数据库

DAO意思是数据库、访问、对象。有了前后端思想。 需要下载mysql&#xff0c;并下载链接自己设置好密码。可以在navicat等软件链接打开。 材料是jc0122.sql&#xff0c;里面的admin_info是要操作的表。不像上一节需要把数据库文件放到java目录里。数据库只要在本地即可。 一、…

浅析Spring的五大类注解和方法注解

简单的将bean对象存储到Spring容器中&#xff0c;可以使用五大类注解实现&#xff0c;也可以通过Bean方法注解实现。本文重点围绕这几个问题展开&#xff1a;1.为什么需要五大类注解&#xff1f;2.五大类注解之间有没有关系&#xff1f;3.Spring使用五大类注解生成beanName问题…

Linux常见命令 17 - 帮助命令 man,whatis,--help,info,help

目录 1. 查看命令/配置文件帮助信息 man 2. 查看简短的命令帮助信息 whatis 3. 查看简短的命令选项信息 --help 4. 另一查看命令文件帮助信息 info 5. Shell内置帮助命令 help 1. 查看命令/配置文件帮助信息 man [1] 语法&#xff1a;man [命令] 示例&#xff1a;如果想要查…

分享129个ASP源码,总有一款适合您

ASP源码 分享129个ASP源码&#xff0c;总有一款适合您 下面是文件的名字&#xff0c;我放了一些图片&#xff0c;文章里不是所有的图主要是放不下...&#xff0c; 129个ASP源码下载链接&#xff1a;https://pan.baidu.com/s/1dUPOSf1BudsK-bB4FnGXfQ?pwdg3ae 提取码&#x…

黑马2021-8Vue自学笔记hm

黑马2021-8Vue教程学习笔记 文章目录黑马2021-8Vue教程学习笔记代码和笔记不断更新gitee代码仓库地址备用前端gei忽略提交文件webpack的使用初始化包管理配置文件 package.json下载webpack解决问题dependencies 和 devDependencies区别:在项目中配置webpackWebpack 中的默认约定…

python基础——列表推导式

python基础——列表推导式 文章目录python基础——列表推导式一、实验目的二、实验原理三、实验环境四、实验内容五、实验步骤一、实验目的 掌握Python数据结构&#xff1a;列表推导式的用法。 二、实验原理 列表推导式&#xff08;list comprehension&#xff09;列表推导式…

【Python百日进阶-Web开发-Linux】Day235 - Win11的WSL2中安装Docker

文章目录一、Docker是什么二、Win11安装Docker2.1 官网下载2.2 系统要求&#x1f517;2.2.1 WSL 2 后端2.2.2 Hyper-V 后端和 Windows 容器2.2.3 关于 Windows 容器2.3 在 Windows 上安装 Docker Desktop2.3.1 交互式安装2.3.2 从命令行安装2.4 启动 Docker 桌面三、WSL2的Ubun…

ConcurrentHashMap的死循环问题

文章目录前言1. 情景复现2. 源码解析3. 代码调试4. 原因5. 解决前言 对于ConcurrentHashMap来说&#xff0c;能保证多线程下的安全问题&#xff0c;但是在JDK1.8中还是会出现一个bug&#xff0c;就是computeIfAbsent&#xff0c;下面就来详细说说死循环的原因 1. 情景复现 首…

进阶C语言 第二章-------《进阶指针》 (指针数组、数组指针、函数指针、回调指针)知识点+基本练习题+深入细节+通俗易懂+完整思维导图+建议收藏

绪论 书接上回&#xff0c;通过对数据类型进阶的认识&#xff0c;你肯定对各种数据类型在内存中如何存储有了了解。虽然说&#xff0c;这方面可能对你的编程能力没什么进步。但是&#xff0c;他是一本内功秘籍&#xff0c;当我们遇到了这方面的问题时我们可以知道可能是哪一方面…

使用 Grafana 请求API接口

目的: 使用Grafana 配合JSON API 插件 请求API接口,完成可视化,实现一些简单的请求功能 假设我们想将如下的API接口返回的json数据可视化 这里借用一下 小熊同学的 金融数据接口 用请求如下接口举例 https://api.doctorxiong.club/v1/fund/detail?code000001&startDat…

色环电容读数方法要点总结

🏡《电子元器件学习目录》 目录 1,概述2,读数方法3,颜色对照表3.1,颜色与电容值数字对照关系表3.2,颜色与10的指数数字对照关系表3.3,颜色与误差对照关系表4,总结1,概述 本文简单介绍色环电容的读数方法。 2,读数方法 如下图所示色环电容共有四个色环。最粗的被命名…

36.Isaac教程--复合消息

复合消息 ISAAC教程合集地址: https://blog.csdn.net/kunhe0512/category_12163211.html 文章目录复合消息测量类型使用复合消息的示例手臂关节速度基本轨迹命令手臂关节和末端执行器命令CompositeMetric 和 CompositeAtlas组件使用 CompositeMetric 计算距离在 Python 脚本中创…

使用bookdown构建新年日记本

简介 一年多前在 B 站发布了一个视频&#xff0c;预览了一下基于 bookdown 构建的日记本。本打算之后更个文字版本教程。结果一直忘了&#xff0c;最近通过一位读者的了解&#xff0c;打算把这个坑补上。 本文内容将展示如何使用 bookdown 模板并修改成自己的日记本。此外&…

某阿里员工提问:年终绩效自己给自己打3.25,会有什么后果?网友回答:必死无疑,不要犯傻!...

年底评绩效&#xff0c;大多数人都会给自己打高绩效&#xff0c;但有些人却反其道而行之。最近&#xff0c;一位阿里员工提出了这样的问题&#xff1a;自评绩效时给自己打3.25&#xff0c;会有什么后果&#xff1f;希望领导能不按常理出牌&#xff0c;给自己3.75。有人问&#…

HashMap1.7中的线程安全问题

文章目录前言正文前言 下面聊聊JDK1.7HashMap的死循环问题&#xff0c;在这之前首先要知道JDK1.7的HashMap底层是数组 链表的形式的 正文 下面给出JDK1.7的扩容代码 //扩容代码 void resize(int newCapacity) {//旧的数组Entry[] oldTable table;//旧的数组长度int oldCap…

SpringBoot+Vue--引入Element-UI创建首页-笔记2

关于Vue项目目录结构介绍 https://tiantian.blog.csdn.net/article/details/128666429?spm1001.2014.3001.5502 先安装引入Element-UI Element - The worlds most popular Vue UI framework i是install的缩写 安装完成后,可以看到package.json里已经引入 在main.js里引入…