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. ...只能放在参数末尾
相关推荐
xys_6781 小时前
JavaEE通关手册:初识Java
java·开发语言
安妮细水长流2 小时前
ad7124
c语言·单片机
ShineWinsu2 小时前
对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析
开发语言·c++·qt·gui·客户端·表格·qtablewidget
曾令胜2 小时前
云服务器被攻击后分析恶意脚本修复漏洞
网络安全·安全威胁分析
ShineWinsu3 小时前
对于Qt:QListWidget常见属性以及QListWidgetItem类的解析
开发语言·c++·qt·客户端·列表·qlistwidget·qlistwidgetitem
吴名氏.4 小时前
Java转AI Agent教程(第十二周)检索与切分
java·开发语言·人工智能·ai·ai agent
瑞雪兆丰年兮4 小时前
JavaWeb-day10-SpringBootWeb案例
java·开发语言·javaweb·web
Elastic 中国社区官方博客4 小时前
更少的位数,相同的召回率:DiskBBQ 更保守的自动校准扫描
大数据·运维·开发语言·人工智能·elasticsearch·搜索引擎
三雷科技5 小时前
第6章第4节:自定义分词器
开发语言·c#
Adellle5 小时前
设计模式指南 (Java 版) ㊁
java·开发语言·设计模式