C语言可变参数

本文详细解释了Linux系统编程中可变参数的实现机制,通过va_list、va_start、va_arg和va_end宏函数的工作原理,帮助读者掌握C语言中如何使用可变参数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

最近学习linux系统编程,看到很多函数都有可变参数,就想了解一下可变参数具体怎么实现的,在网上找了几个文章,都不怎么易懂,结合他们写的以及去看源码实现,才彻底理解,写下这篇博客,以后自己忘了再来看看

前提小知识: 函数参数是从右往左依次压入栈的,最低地址cnt,最高地址为最后一个参数

先来看一个小demo

#include<stdio.h>
#include<stdlib.h>
#include<stdarg.h>

void sum(int cnt, ...)
{
	va_list args;
	va_start(args, cnt);
	int i = 0;
	int ret = 0;
	while (i < cnt)
	{
		ret += va_arg(args, int);
		++i;
	}
	va_end(args);
	printf("ret = %d\n", ret);
}

int main()
{
	sum(10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10);

	return 0;
}

以上是一个用可变参数实现的sum函数,第一个参数为总共有几个数相加,后面则是要进行相加的参数,首先介绍一下va_list 从名字可以看出这是一个链表,下面是va_list源码

typedef struct {
	char *a0;	/* pointer to first homed integer argument */
	int offset;	/* byte offset of next parameter */
} va_list;

这是一个链表,实际上并没有链子,它只指向一块空间,他会在va_start进行初始化,下面是va_start,va_args,va_end 宏函数源码

#define _INTSIZEOF(n)	( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) )
#define va_start(ap,v)	( ap = (va_list)&v + _INTSIZEOF(v) )
#define va_arg(ap,t)	( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
#define va_end(ap)	( ap = (va_list)0 )

_INTSIZEOF(N)

这个宏是用做内存对齐的,如果N的大小在1 - 4 之间那么他会返回4,4 - 8之间会返回8,内置类型,效果和sizeof没差

va_start

ap是va_list结构体变量,v是函数参数中的第一个参数,将v强转为va_list类型,再加v本身大小,就能找到可变参数的第一个参数地址,也就是sum函数的第二个参数地址,因为v是第一个参数,加上他本身的大小就是跳过了自身,来到了紧邻自身后的第一个地址,这点相信有C指针基础的可以很容易理解,而通过前提知识,参数地址是紧挨着的,所以加了第一个参数大小,就到了第二个参数,并且让ap指向了这一参数地址

va_arg

ap依旧是va_list类型,t为type简写,ap+=t本身大小后返回一个ap加之前的值,并强转为t*再解引用,

如果看不懂这个,就把他想象成 i++后,返回的是i加之前的值,是一回事,这个宏函数的作用就是取出ap的值,ap在start时指向了第二参数,也就是取第二参数的值,并将ap指向下一个参数地址

va_end

这个就很简单了,就是把ap置位空指针,C的空指针就是0

明白这三个后,再去看一下前面的小demo就非常轻松易懂了,也就能理解C语言可变参数是怎么实现的了

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值