C 可变量参数

函数参数分类

  1. 基本类型参数:int、float、char等,传递时传递值拷贝,函数内部修改不会影响外部原变量
  2. 复杂类型参数:数组、结构体、指针
    ○ 数组:传参时自动退化为指针,函数内拿到的是数组首地址
    ○ 结构体:可以传值(拷贝整个结构体),也可以传结构体指针(推荐,节省拷贝开销)
    基本类型参数定义时必须写类型,void func(int a),不能省略类型

可变参数(不定量参数)基础

  1. 关键字:... 省略号,表示可变参数列表
  2. 头文件:<stdarg.h>,提供va_list、va_start、va_arg、va_end这一组宏
  3. 语法规则:可变参数...必须放在参数列表最后面,前面至少要有 1 个固定参数
c 复制代码
int Sum(int count, ...);// ✅合法
int Sum(...);           // ❌错误,...不能放前面

四大可变参数宏

宏 作用
va_list ap; 定义一个可变参数迭代器变量 ap,本质是指针
va_start(ap, 固定参数名) 初始化 ap,让 ap 指向第一个可变参数;必须指定最后一个固定参数
va_arg(ap,类型) 取出当前 ap 指向的参数,并且 ap 自动移动到下一个参数;必须指定正确类型
va_end(ap) 清理 ap,结束可变参数读取,防止内存问题
c 复制代码
#include <stdio.h>
#include <stdarg.h>
// count:传入参数个数,后面是可变参数
int Sum(int count, ...)
{
    va_list ap;
    va_start(ap, count); // ap指向第一个可变参数
    int res = 0;
    for(int i = 0; i < count; i++)
    {
        res += va_arg(ap, int); // 取出int类型参数
    }
    va_end(ap); // 收尾
    return res;
}
int main(void)
{
    printf("%d\n", Sum(3,10,20,30)); // 3个参数:10+20+30
    return 0;
}

printf 原理

c 复制代码
int printf(const char *format, ...);
  1. format是固定参数(格式化字符串),后面...接收任意数量、任意类型参数
  2. 通过解析format字符串里的%d %f %s,判断后面可变参数的类型,再调用va_arg取出对应参数
    ⚠️坑:格式符和实际参数类型不匹配,会直接得到乱码(未定义行为),va_arg不会自动识别类型,你写什么类型它就取多少字节

底层 & 反汇编视角

va_start 的底层:拿到栈上可变参数区域的起始地址,ap 本质就是栈指针

  1. 可变参数本质:调用方把所有参数按调用约定放到寄存器 / 栈上;被调用函数靠 va 系列宏,手动遍历这片内存
  2. 没有任何机制帮你记录:可变参数一共有多少个、每个是什么类型!必须靠固定参数传递信息(printf 靠字符串标记、Sum 靠 count)
  3. 调试:断点进可变参数函数,查看ap的值,内存窗口跟着 ap 查看栈上参数;反汇编能看到 va_start/va_arg 展开后的内存读写指令

可变参数常见坑

  1. 不能自动识别参数数量、类型,类型写错直接读错内存
  2. va_arg类型不能写char/short,可变参数会默认整型提升,char 会被提升为 int
  3. va_start、va_end必须成对使用
  4. ...只能放在参数末尾
相关推荐
andyweike1 小时前
kotlin dsl library工程怎么配置
android·开发语言·kotlin
huaweichenai1 小时前
php搭建mcp服务
开发语言·php·ai编程
估值探索者1 小时前
【Python量化技术指标实战 02】MACD金叉也分强弱?手工算一次 DIF/DEA 就懂了
java·开发语言·python·股票数据·股票数据api接口
讳疾忌医丶1 小时前
编译器眼中的 C++ 循环:从指针别名、IEEE 754 结合律到 SIMD 语义证明
开发语言·c++
小莞尔1 小时前
【51单片机】【protues仿真】基于51单片机六路抢答器系统
c语言·单片机·嵌入式硬件·物联网·51单片机
重生六道2 小时前
B站视频时长统计:一段JS脚本搞定分P/合集总时长(附倍速计算)
开发语言·javascript·音视频
XiYang-DING2 小时前
P5528.带过期时间的 LRU 缓存
java·开发语言·缓存
小徐不徐说2 小时前
C++ 机器视觉入门:从零搭建 AOI 开发环境(OpenCV + CMake)
开发语言·c++·opencv
zhangx1234_2 小时前
javaEE 多线程4
java·开发语言