问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

va_start和va_end使用介绍

创作时间:
作者:
@小白创作中心

va_start和va_end使用介绍

引用
CSDN
1.
https://blog.csdn.net/kupepoem/article/details/139487592

一、概述

在C语言编程中,函数的形式参数数目通常是确定的,调用时需要依次给出与形式参数对应的所有实际参数。但在某些情况下,希望函数的参数个数可以根据需要确定。例如,我们熟悉的printf()scanf()和系统调用execl()等函数。那么它们是如何实现的呢?

C编译器通常提供了一系列处理这种情况的宏,以屏蔽不同的硬件平台造成的差异,增加程序的可移植性。这些宏包括va_startva_argva_end等。在讲解这些宏之前,我们先了解一下调用函数时传入参数的处理过程。

在C语言中,当我们无法列出传递函数的所有实参的类型和数目时,可以用省略号指定参数表:

void demo(...);
void demo(parm_list,...);

这种方式与我们以前认识的函数参数列表不同,但需要记住这是C语言中一种传参的形式,在后面我们就会用到它。

二、原理

函数参数是以数据结构栈的形式存取,从右至左入栈。

举个例子:

void demo(int x, float y, char z);

那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z。因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指针移位运算,则总可以顺藤摸瓜找到其他的输入变量。

下面是 <stdarg.h> 里面重要的几个宏定义:

假设有一个函数:void demo(char para, ...);

typedef char* va_list;
void va_start(va_list ap, para); /* ANSI version */
type va_arg(va_list ap, type);
void va_end(va_list ap);

va_list 是一个字符指针,可以理解为指向当前参数的一个指针,取参必须通过这个指针进行。

  1. 在调用参数表之前,定义一个 va_list 类型的变量(假设为 ap);
  2. 应该对 ap 进行初始化,让它指向"可变参数表"里面的第一个参数,通过调用 va_start 来实现的,第一个参数是 ap 本身,第二个参数是在"变参表"前面紧挨着的变量即 para,也就是“...”之前的那个参数;可变参数表就是“...”,简称变参表。
  3. 若想获取参数,调用 va_arg,它的第一个参数是 ap,第二个参数是要获取参数的类型,然后返回此类型的值,这两个类型必须一致,并把 ap 的位置指向"变参表"的下一个变量位置;
  4. 获取所有的参数之后,有必要将这个 ap 指针关掉,以免发生危险,调用 va_end 方法将输入参数 ap 置为 NULL,应该养成获取完参数表之后关闭指针的习惯。

三、示例

© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号