C 语言可变参数

C 语言可变参数

1. 背景

​ C 语言是支持可变参数的,比如标准输入输出等库函数都是支持多个函数入参的,有时我们也想让自己的函数支持可变参数,如何实现?其原理又是什么?

2. 基础知识

  • 函数入参是保存在栈中的
  • 函数入参压栈顺序为依次从右向左压栈
  • 一般情况下的栈是向下生长的

3. 实现

​ 通过以下代码分析函数入参:

void log_output(int a, int b, const char *p)
{
	printf("0x%p\n",&a);
	printf("0x%p\n", &b);
	printf("0x%p\n", &p);
}
/*
输出结果
0x0000003FB9EFFBE0
0x0000003FB9EFFBE8
0x0000003FB9EFFBF0
*/

​ 通过输出地址发现(我的机器是 64 位的,一个地址占用 8 个字节),三个入参的地址是连续的,且 &a < &b < &p,因此压栈顺序确实是从右向左压,因此我们可以通过压栈这一特性将栈中的内容取出来即可,修改后的代码如下:

void log_output(const char* fmt, ...)
{
	char* p;
	printf("%s", fmt); //第一个参数
	p = ((char*)&fmt) + sizeof(fmt); // 第二个参数的地址
	printf("%s", *(char **)p);
	p += sizeof(fmt); // 第三个参数的地址
	printf("%s\n", *(char**)p);
}

int main(void)
{
	log_output("hello", " world", "!");
}

/*
输出结果
hello world!
*/

​ 任何一个可变参数的函数都必须至少包含一个固定参数,可选参数由于数目不定(0个或以上)使用 … 表示,其实上述通过直接操作地址的方式就是 C 语言 stdarg.h 这个标准头文件中的实现,在这个头文件中将指针操作通过宏的方式给封装起来,使用 stdarg.h 提供的宏实现如下:

void log_output(const char* fmt, ...)
{
	va_list args;
	va_start(args, fmt);

	printf("%d ",va_arg(args, int));
	printf("%d ",va_arg(args, int));
	printf("%s",va_arg(args, char *));

	va_end(args);
}

int main(void)
{
	log_output("%d %d %s",8,6,"hello world!");
	return 0;
}

/*
输出结果
8 6 hello world!
*/
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值