C语言小知识-不定参数函数实现

2023-10-31

C语言不定参数的实现


C语言在定义函数参数时,允许参数的使用数量可变,这在C语言中称为 可变参数函数(variadic function) 当然在C标准库中不乏可变参数函数的使用,例如:

C标准函数 printf 的声明方式为:int printf(const char *fmt, …);
C标准函数 scanf 的声明方式为:int scanf(const char * fmt, …);

它们有共同的特点:

  1. 函数都有一个强制参数
  2. 后面跟着的参数的个数和类型是可变的(用三个点“…”做参数占位符)

在使用C语言不定参数时需要包含C标准库 <stdarg.h> ,该标准库文件提供了实现可变参数功能的函数和宏,其中主要使用的几个函数和宏定义如下:

  1. va_list:用来保存宏va_start1、va_arg和va_end所需信息的一种类型。为了访问变长参数列表中的参数,必须声明 va_list 类型的一个对象。

  2. va_start: 访问变长参数列表中的参数之前使用的宏,它初始化用 va_list 声明的对象,初始化结果供宏 va_arg 和 va_end 使用;

  3. va_arg: 展开成一个表达式的宏,该表达式具有变长参数列表中下一个参数的值和类型。每次调用 va_arg 都会修改用 va_list 声明的对象,从而使该对象指向参数列表中的下一个参数;

  4. va_end: 该宏使程序能够从变长参数列表用宏 va_start 引用的函数中正常返回。

C标准库 <stdarg.h>

可使用不同的编译器打开C标准库 <stdarg.h> 进行查看,可能不同平台以及不同版本存在些许差异,但效果是一样的。

在Visual Studio 2019打开标准库 <stdarg.h> 后代码如下:

//
// stdarg.h
//
//      Copyright (c) Microsoft Corporation. All rights reserved.
//
// The C Standard Library <stdarg.h> header.
//
#pragma once
#define _INC_STDARG

#include <vcruntime.h>

#pragma warning(push)
#pragma warning(disable: _VCRUNTIME_DISABLED_WARNINGS)

_CRT_BEGIN_C_HEADER



#define va_start __crt_va_start
#define va_arg   __crt_va_arg
#define va_end   __crt_va_end
#define va_copy(destination, source) ((destination) = (source))



_CRT_END_C_HEADER

#pragma warning(pop) // _VCRUNTIME_DISABLED_WARNINGS

在DevC++中打开如下:

/* Copyright (C) 1989, 1997, 1998, 1999, 2000 Free Software Foundation, Inc.

This file is part of GCC.

GCC is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2, or (at your option)
any later version.

GCC is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with GCC; see the file COPYING.  If not, write to
the Free Software Foundation, 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.  */

/* As a special exception, if you include this header file into source
   files compiled by GCC, this header file does not by itself cause
   the resulting executable to be covered by the GNU General Public
   License.  This exception does not however invalidate any other
   reasons why the executable file might be covered by the GNU General
   Public License.  */

/*
 * ISO C Standard:  7.15  Variable arguments  <stdarg.h>
 */

#if defined(__GNUC__)

#ifndef _STDARG_H
#ifndef _ANSI_STDARG_H_
#ifndef __need___va_list
#define _STDARG_H
#define _ANSI_STDARG_H_
#endif /* not __need___va_list */
#undef __need___va_list

/* Define __gnuc_va_list.  */

#ifndef __GNUC_VA_LIST
#define __GNUC_VA_LIST
typedef __builtin_va_list __gnuc_va_list;
#endif

/* Define the standard macros for the user,
   if this invocation was from the user program.  */
#ifdef _STDARG_H

#define va_start(v,l)	__builtin_va_start(v,l)
#define va_end(v)	__builtin_va_end(v)
#define va_arg(v,l)	__builtin_va_arg(v,l)
#if !defined(__STRICT_ANSI__) || __STDC_VERSION__ + 0 >= 199900L || defined(__GXX_EXPERIMENTAL_CXX0X__)
#define va_copy(d,s)	__builtin_va_copy(d,s)
#endif
#define __va_copy(d,s)	__builtin_va_copy(d,s)

/* Define va_list, if desired, from __gnuc_va_list. */
/* We deliberately do not define va_list when called from
   stdio.h, because ANSI C says that stdio.h is not supposed to define
   va_list.  stdio.h needs to have access to that data type, 
   but must not use that name.  It should use the name __gnuc_va_list,
   which is safe because it is reserved for the implementation.  */

#ifdef _HIDDEN_VA_LIST  /* On OSF1, this means varargs.h is "half-loaded".  */
#undef _VA_LIST
#endif

#ifdef _BSD_VA_LIST
#undef _BSD_VA_LIST
#endif

#if defined(__svr4__) || (defined(_SCO_DS) && !defined(__VA_LIST))
/* SVR4.2 uses _VA_LIST for an internal alias for va_list,
   so we must avoid testing it and setting it here.
   SVR4 uses _VA_LIST as a flag in stdarg.h, but we should
   have no conflict with that.  */
#ifndef _VA_LIST_
#define _VA_LIST_
#ifdef __i860__
#ifndef _VA_LIST
#define _VA_LIST va_list
#endif
#endif /* __i860__ */
typedef __gnuc_va_list va_list;
#ifdef _SCO_DS
#define __VA_LIST
#endif
#endif /* _VA_LIST_ */
#else /* not __svr4__ || _SCO_DS */

/* The macro _VA_LIST_ is the same thing used by this file in Ultrix.
   But on BSD NET2 we must not test or define or undef it.
   (Note that the comments in NET 2's ansi.h
   are incorrect for _VA_LIST_--see stdio.h!)  */
#if !defined (_VA_LIST_) || defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__) || defined(WINNT)
/* The macro _VA_LIST_DEFINED is used in Windows NT 3.5  */
#ifndef _VA_LIST_DEFINED
/* The macro _VA_LIST is used in SCO Unix 3.2.  */
#ifndef _VA_LIST
/* The macro _VA_LIST_T_H is used in the Bull dpx2  */
#ifndef _VA_LIST_T_H
/* The macro __va_list__ is used by BeOS.  */
#ifndef __va_list__
typedef __gnuc_va_list va_list;
#endif /* not __va_list__ */
#endif /* not _VA_LIST_T_H */
#endif /* not _VA_LIST */
#endif /* not _VA_LIST_DEFINED */
#if !(defined (__BSD_NET2__) || defined (____386BSD____) || defined (__bsdi__) || defined (__sequent__) || defined (__FreeBSD__))
#define _VA_LIST_
#endif
#ifndef _VA_LIST
#define _VA_LIST
#endif
#ifndef _VA_LIST_DEFINED
#define _VA_LIST_DEFINED
#endif
#ifndef _VA_LIST_T_H
#define _VA_LIST_T_H
#endif
#ifndef __va_list__
#define __va_list__
#endif

#endif /* not _VA_LIST_, except on certain systems */

#endif /* not __svr4__ */

#endif /* _STDARG_H */

#endif /* not _ANSI_STDARG_H_ */
#endif /* not _STDARG_H */

#endif /*__GNUC__ */

/* include mingw stuff */
#include <_mingw_stdarg.h>

下面给出不定参数的一个小例子

void _vaTest(char* fmt, ...)
{
	va_list va_args;
	int d = 0;
	double f = 0.0;
	char c = '\0';
	char* s = NULL;
	va_start(va_args, fmt);
	while (*fmt != '\0')
	{
		switch (*fmt)
		{
			case '%':
				++fmt;
				switch (*fmt)
				{
				case 'd':
					d = va_arg(va_args, int);
					break;
				case 'f':
					f = va_arg(va_args, double);
					break;
				case 'c':
					c = va_arg(va_args, char);
					break;
				case 's':
					s = va_arg(va_args, char*);
					break;
				}
				++fmt;
				break;
			default:
				putchar(*fmt);
				break;
		}
	}
	va_end(va_args);
}

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C语言小知识-不定参数函数实现 的相关文章

  • linux 设置端口密码,SSH更改默认端口号及实现免密码远程登陆

    近来在复习防火墙管理工具 iptables 的基本使用方法 涉及到对端口添加或删除防火墙策略的内容 之前对ssh更改默认端口号及免密码登录的方法不熟悉 这次做一个基本的总结防止自己遗忘 错误偏差及其他经验之处 还望各位多多支出 系统环境 两
  • 自定义横向ProgressBar样式圆角改直角

    横向progressBar的progress部分是圆角的 如果background是直角 那看起来不怎么和谐 所以这篇博文介绍progress部分改直角 在drawable目录下新建一个 progress style xml
  • R语言 第3章 R语言常用的数据管理(2)

    关注公众号凡花花的小窝 收获更多的考研计算机专业编程相关的资料 字符串处理 正则表达其实就是对文本进行模式匹配 所有语言中的正则表达式都有一些共同的特征 我们使用help regex 命令查看R正则表达的帮助内容 在我看来 正则表达式的主要
  • umi框架实战项目

    29 9React课程 第10节 umi框架实战项目 第10节 umi框架实战项目 第10节 umi框架实战项目 Generator是异步解决方案 next执行下一个步骤 可以放在后面也可以放在前面 Yield表示暂停 import Rea
  • [已解决]java.lang.NoClassDefFoundError: com/google/common/base/Function

    为了解决inject的报错 pom已经被我改乱了 结果最后即便改过来 项目编译报了以上错误 据说是缺少一个jar包 我用的是selenium 2 46 0 所以需要下载对应版本 selenium server standalone 2 46

随机推荐

  • Sentinel高并发解决方案

    Sentinel 承接了阿里巴巴近 10 年的双十一大促流量的核心场景 本文介绍阿里开源限流熔断方案 Sentinel 功能 原理 架构 快速入门以及相关框架比较 基本介绍 1 名词解释 服务限流 当系统资源不够 不足以应对大量请求 对系统
  • 常见异常解析

    ConcurrentHashMap与CopyOnWriteArrayList比较 博客分类 Java ConcurrentHashMap ConcurrentHashMap引入了Segment 每个Segment又是一个hashtable
  • LeetCode 之 剑指 Offer 21. 调整数组顺序使奇数位于偶数前面(Java)

    文章目录 LeetCode 之 剑指 Offer 21 调整数组顺序使奇数位于偶数前面 Java 一 题目 二 解题思路 三 代码 LeetCode 之 剑指 Offer 21 调整数组顺序使奇数位于偶数前面 Java 一 题目 剑指 Of
  • QuaggaJS在给定图像中定位条形码的工作原理

    QuaggaJS在给定图像中定位条形码的工作原理 一 介绍 二 步骤 1 创建图像的二进制表示 2 将图像切成网格 20 x 15个单元 3 提取每个细胞的骨架 4 组件标记 5 确定组件的方向 6 测定细胞质量 7 查找连接的单元格 8
  • PDF去水印教程

    现在的互联网时代是一个共享的时代 我们一定会经常从网络上面下载一些文件资料等等 那么是不是经常会遇到一些网站上的PDF文件会含有该网站的水印或者网址链接等等 这些水印有时候会影响我们正常的阅读文件 那么我们就需要将他们都去掉 接下来我们就是
  • java利用条件运算符的嵌套来完成此题:学习成绩> =90分.....(java50道经典编程题)

    题目 利用条件运算符的嵌套来完成此题 学习成绩 gt 90分的同学用A表示 60 89分之间的用B表示 60分以下的用C表示 这是一个写条件运算的例子 先和大家聊一下条件运算符 所谓条件运算也是比较简单的格式如下 基本格式 条件 值1 值2
  • AD9910模块高速DDS模块、功能性能讲解、开发调试注意事项、代码详解、电子设计大赛DDS

    AD9910模块高速DDS模块 STM32 驱动代码 功能性能讲解 开发调试注意事项 代码详解 电子设计大赛DDS 目录 AD9910模块高速DDS模块 STM32 驱动代码 功能性能讲解 开发调试注意事项 代码详解 电子设计大赛DDS 1
  • 稀疏数组和二维数组转换(以及持久化io实现)

    稀疏数组 1 当一个数组中大部分元素为0 或者为同一值的数组时 可以使用稀疏数组来保存数组 2 稀疏数组的处理方式是 a 记录数组一共有几行几列 有多少个不同值 b 把具有不同值元素的行 列及值记录在一个小规模的数组中 从而缩小程序的规模
  • 遥感影像深度学习样本制作

    交流QQ 3239516597 对于遥感同学 在学习深度学习时 第一步就要解决遥感数据样本的制作 遥感影像数据的样本根据不同的应用也有所不同 不知道的同学可以去看视频 遥感深度学习样本制作视频1 今天介绍一下如果已经有了遥感影像和对应的类别
  • 地址栏输入 URL 敲下回车后发生了什么

    浏览器地址栏输入 URL 回车后发生了什么 一 总结分析 分析如下 从输入 URL到回车后发生的行为如下 URL解析 DNS 查询 TCP 连接 HTTP 请求 响应请求 页面渲染 URL解析 首先判断你输入的是一个合法的URL 还是一个待
  • 定位排查Java线上内存溢出问题(服务重启,没有捕获到日志)

    一 场景 线上项目device服务模块内存不断上涨导致CPU较高 导致触发脚本执行重启 接口自动化测试平台不断的报500拒绝连接等错误提示 排查 通过服务器日志查询并没有异常错误信息打印 查看docker容器的日志发现错误是打印控制台 无法
  • 简单工厂模式

    定义 定义一个工厂类 它可以根据传入的参数返回不同类的实例 被创建的类实例通常都具有相同的父类 因为在简单工厂模式中返回所创建的类实例的方法是静态方法 所以简单工厂模式也称为静态工厂模式 简单工厂方法的要点在于 你只需要传入一个正确的参数
  • 安装Yearning SQL审核平台和Inception(基于已闭源方式)

    这是我安装Yearning SQL审核平台和Inception 已闭源 总结的文档 1 安装centos7并配置网络为桥接模式 命令 vi etc sysconfig network scripts ifcfg ens33 内部配置如下 2
  • 硬件学习--不同硬盘类型速度对比

    SATA 串行ATA总线 SCSI 小型电脑输入输出接口 SAS 希捷研究出来的取代SCSI技术的接口 SSD 固态硬盘 容量小 读写快 接口速度是 SSD gt SAS gt SCSI gt SATA SAS Serial Attache
  • 通用Ajax设计

    利用Servlet和反射技术实现通用的Ajax调用设计 如下 一 调用规则 在JS代码 调用者只需按下面的规范 即可实现异步或同步java方法调用 在你的jsp或html页面中 导入通用异步调用方法文件 km js 自定义 然后写异步调用方
  • unity中使用c#钩子

    目的 解决在应用程序最小化后无法监听到系统按键事件的情况 解决问题的过程很好笑 我先找到了第一个方法 脚本一 使用方法 脚本挂在场景中物体上即可 using System using System Collections using Sys
  • 统计学习第四弹--随机变量的概率分布

    关于随机变量概率分布的重要概念 概率 对事件的发生的可能性大小的度量值 随机变量 事先不能确定其取值的变量 离散型随机变量 只能取有限个值的随机变量 连续型随机变量 可以取一个或多个区间中任何值的随机变量 期望值 随机变量的平均取值 求法是
  • Caltech数据使用详情

    Caltech官网 http www vision caltech edu Image Datasets CaltechPedestrians 以Caltech测试集为例 大概是4095个图片吧 1 下载数据 http www vision
  • 【华为OD机试】返回矩阵中非1的元素个数【2023 B卷

    华为OD机试 真题 点这里 华为OD机试 真题考点分类 点这里 题目描述 存在一个m n的二维数组 其成员取值范围为0 1 2 其中值为1的元素具备同化特性 每经过1S 将上下左右值为0的元素同化为1 而值为2的元素 免疫同化 将数组所有成
  • C语言小知识-不定参数函数实现

    C语言不定参数的实现 C语言在定义函数参数时 允许参数的使用数量可变 这在C语言中称为 可变参数函数 variadic function 当然在C标准库中不乏可变参数函数的使用 例如 C标准函数 printf 的声明方式为 int prin