va_list、va_start、va_arg、va_end

c语言实现可变参数的方式是利用函数参数入栈从右到左的的顺序,如果知道任意参数地址,且知道参数类型,则可以通过指针移动取出参数值。
比如函数void fun(int a,int x,int y,int z)入栈顺序如下
在这里插入图片描述
再看va_list、va_start、va_arg、va_end,这几个是定义在stdarg.h的宏定义

typedef char* va_list;
#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 ) // 将指针置为无效

void va_start ( va_list ap, prev_param ); /* ANSI version */
type va_arg ( va_list ap, type ); 
void va_end ( va_list ap ); 

_INTSIZEOF(n)

  • 是求n变量的sizeof之后再对int字节对齐,比如sizeof(n)=1,则_INTSIZEOF(n)=4,sizeof(n)=3,则_INTSIZEOF(n)=8

va_start(ap,v)

  • 是让ap指向v变量的下一个变量,如果对于void fun(int a,int x,int y,int z),va_start(ap,x),则ap指向x的地址

va_arg(ap,t)

  • ap指向下一个变量地址,并返回ap加_INTSIZEOF(t)之前地址里面的值(注意ap一直在增加)

va_end(ap)

  • 将ap设置为NULL

下面是一个例子

#include <stdio.h>
#include <stdarg.h>
int va_printf_demo(int num,...)
{
	va_list p_arg;
	va_start(p_arg,num);
	for(int i=0;i<num;i++)
	{
		printf("%s ",va_arg(p_arg,char*));
	}
	va_end(p_arg);
	printf("\n");
}
int main(int argc,char**argv)
{
	va_printf_demo(4,"a","b","c","d");
	return 0;
}

结果
在这里插入图片描述

再来看下printf可以怎么实现

const unsigned char cr = '\r';
int printf(const char* format, ...)
{
  int i;
  va_list va;
  va_start(va, format);
  char buffer[256];
  int ret = vsnprintf(buffer, 256, format, va);
  va_end(va);
  for (i = 0; i < ret; ++i) {
    if(buffer[i] == '\n')
    {
      drv_uart_write_fifo(&cr,1,UART_BLOCKING);
    }
    drv_uart_write_fifo((unsigned char*)&buffer[i],1,UART_BLOCKING);
  }
  return ret;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值