首页 > 其他分享 >自己实现一个简单可变参数函数

自己实现一个简单可变参数函数

时间:2024-11-03 22:08:19浏览次数:3  
标签:va 函数 int ap INTSIZEOF 参数 可变

什么是可变参数

在C语言编程中有时会遇到一些参数可变的函数、例如printf()、scanf(),其函数原型为:

int printf(const char *format,...)
int scanf(const char *format,...)

它除了有一个参数format固定以外,后面的参数其个数和类型都是可变的,用三个点"..."作为参数占位符号。

参数列表的构成

任何一个可变参数都可以分为两个部分:固定参数和可选参数。至少有一个固定参数,其声明与普通函数声明相同;可选参数由于数目不定(0个或以上),声明时必须用"..."表示。固定参数和可选参数共同构成的可变参数函数的参数列表。

实现原理

C语言中使用va_list系列变参宏实现变参函数,此处va意为variable-argument(可变参数)。
x86平台VC6.0集成开发环境中,stdarg.h头文件内变参宏定义如下:

typedef char *va_list;

// 把n 圆整到sizeof(int)的倍数
#define _INTSIZEOF(n)((sizeof(n)+sizeof(int)-1)& ~(sizeof(int)-1))

//初始化 ap指针,使其指向第一个可变参数。v是变参列表的前一个参数
#define va_start(ap,v) (ap = (va_list)&v + _INTSIZEOF(v))

//该宏返回当前变参值,并使ap指向列表中的下一个变参
#define va_arg(ap,type) (*(type *)((ap +=_INTSIZEOF(type) - _INTSIZEOF(type))))

//将指针ap置为无效,结束变参的获取
#define va_end(ap)  (ap = (va_list)0)

_INTSIZEOF(n)****
_INTSIZEOF宏考虑到某些系统需要内存地址对齐。从宏名看应按照sizeof(int)即栈粒度对齐,参数在内存中的地址均为sizeof(int) = 4的倍数。
例如,若1<= sizeof(n)<=4,则_INTSIZEOF(n) = 4;
若5<=sizeof(n)<=8,则_INTSIZEOF(n) = 8。

va_start(ap,v)
va_start宏首先根据(va_list)&v得到参数v在栈中的内存地址,加上_INTSIZEOF(v)所占内存大小后,使ap指向v的下一个参数。在使用的时候,一般用这个宏初始化ap指针,v是变参列表的前一个参数,即最后一个固定参数,初始化的结果是ap指向第一个变参。

va_arg(ap,type)
这个宏取得type类型的可变参数值。首先ap +=_INTSIZEOF(type),即ap跳过当前可变参数而指向下个变参的地址;然后ap-_INTSIZEOF(type)
得到当前变参的内存地址,类型转换后解引用,最后返回当前变参值。

自己实现一个可变参函数

#include <stdio.h>
//模拟可变参数函数,用于计算多个整数的和
int sum(int count, int first, ...)
{
    int total = first;
    //创建指向第一个可变参数的指针
    int* p = &first;
    //遍历所有的参数
    for (size_t i = 1; i < count; i++)
    {
        p++;//移动到下一个参数位置
        total += *p;//解引用并添加
    }
    return total;
}
int main()
{
    int result = sum(5,1,2,3,4,5);
    printf("sum::%d\r\n", result);
    return 0;
}

可变参应注意的事项

  • 确保第一个参数指定可变参数的数量和类型
  • 使用正确的类型读取参数
  • 可变参数的类型一致性
  • 可变参数不能是数组和结构体
  • 可变参函数不进行类型检查
  • 小心浮点类型的默认提升
  • 避免在循环中使用可变参数
  • 使用标准库宏来避免手动解析

标签:va,函数,int,ap,INTSIZEOF,参数,可变
From: https://www.cnblogs.com/doubleconquer/p/18211832

相关文章

  • Sigrity Power SI 3D-EM Full Wave Extraction模式如何进行S参数提取和观测3D电磁场和
    SigrityPowerSI3D-EMFullWaveExtraction模式如何进行S参数提取和观测3D电磁场和远场操作指导(三)-去嵌SigrityPowerSI3D-EMFullWaveExtraction模式如何进行S参数提取和观测3D电磁场和远场操作指导(三)-去嵌  SigrityPowerSI如何使用3D-EMFullWaveExtracti......
  • 距离函数求周长
    题目描述给出平面坐标上不在一条直线上三个点坐标 (x1,y1),(x2,y2),(x3,y3)(x1​,y1​),(x2​,y2​),(x3​,y3​),坐标值是实数,且绝对值不超过100.00,求围成的三角形周长。保留两位小数。对于平面上的两个点 (x1,y1),(x2,y2)(x1​,y1​),(x2​,y2​),则这两个点之间的距离 d......
  • 科普文:软件架构数据库系列之【MySQL:innodb buffer pool功能特性及其关键参数】
    一、概述InnoDB的BufferPool是其存储引擎中非常重要的一个组件,它的主要功能是缓存数据和索引页,以减少磁盘I/O操作,从而提高查询性能。科普文:软件架构数据库系列之【MySQL5.7的InnoDB引擎存储结构分析:buffer+disk】_mysql5.7innodb存储引擎架构-CSDN博客科普文:软件架构......
  • FastAPI 路径参数详解:动态路径与数据校验的灵活实现
    FastAPI路径参数详解:动态路径与数据校验的灵活实现本文全面介绍了在FastAPI中使用路径参数的技巧和实现方式。路径参数允许API动态响应不同路径中的请求信息,结合URL(UniformResourceLocator)和URI(UniformResourceIdentifier)进行资源定位和标识。URL是指资源的完......
  • C语言:函数
    一.自定义函数自定义函数形式如下:ret_type fun_name(形式参数){}ps:1.ret_type是函数返回类型,有时候是void,表示什么都不返回2.fun_name是函数名,尽量清楚明了3.括号中放的是形式参数,有时候是void,表示没有参数,如果有参数记得加入参数的类型和......
  • 工程师和科学家的高等数学及python实例:2三角函数 II
    2三角函数II学完本章内容后,你应该能够●讨论反三角函数的图形●讨论倒数函数的图形●评估正弦、余弦和正切函数的变换2.1引言本章将继续讨论三角函数,研究上一章中涉及的三个三角函数的倒数和反三角函数。本章还将讨论这些函数的变换。2.2三角函数的倒数正弦、余弦......
  • 【笔记/模板】KMP 与 Z 函数
    前缀函数前缀函数通常称为border,一个字符串\(S\)的border定义为它的一个前缀子串\(t(t\neS)\),满足\(t\)既是\(S\)的前缀,也是\(S\)的后缀。下文的border均为\(S\)的最长border长度。简单来说,对于一个字符串\(S=\texttt{abcabcd}\)(下标从\(1\)开始),它的前......