定义一个不定参数的函数

int my_printf(const char *fmt, ...)

不定参数存放在哪

传递参数是依次存放在栈中传递的,不定参数存放在固定参数的后面

怎么读取不定参数的数值

内存中不定参数,4字节对齐,对于指针变量,只储存指针变量的指针所指地址。
可以定义一些宏来对不定参数的读取进行操作,这些宏在后面会用到

typedef char *  va_list;
//数据类型的长度计算,四字节对齐
#define _INTSIZEOF(n)   ( (sizeof(n) + sizeof(int) - 1) & ~(sizeof(int) - 1) ) //把ap指针移动到v的最后面
#define va_start(ap,v)  ( ap = (va_list)&v + _INTSIZEOF(v) )  //返回ap内的数值,然后将ap指针后移
//#define va_arg(ap,t)    ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )  //防止野指针的存在
#define va_end(ap)      ( ap = (va_list)0 )

函数简单的举例

int printf(const char *fmt, ...)
{char str[110] = {0};uint8_t offset = 0;va_list ap;va_start(ap, fmt); for(; *fmt != '\0'; fmt++){if (*fmt != '%') {offset = load_c(str,offset,*fmt);continue;}fmt++;switch(*fmt){case 'u':offset = load_data(str,offset ,va_arg(ap, unsigned int));break;case 's':offset = load_string(str,offset ,va_arg(ap, char *));break;case 'f':offset = load_fdata(str,offset ,va_arg(ap, unsigned int));break;default:offset = load_c(str,offset,*fmt);break;}if(offset >= 100)break;}va_end(ap);uart_send_str(str);return 0;
}

上面函数所调用的函数

/**  value: 要转换的整数,string: 转换后的字符串,radix: 转换进制数,如2,8,10,16 进制等。*/
static char* itoa(int num,char* str,int radix)
{char index[]="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";//索引表unsigned unum;//存放要转换的整数的绝对值,转换的整数可能是负数int i=0,j,k;//i用来指示设置字符串相应位,转换之后i其实就是字符串的长度;转换后顺序是逆序的,有正负的情况,k用来指示调整顺序的开始位置;j用来指示调整顺序时的交换。//获取要转换的整数的绝对值if(radix==10&&num<0)//要转换成十进制数并且是负数{unum=(unsigned)-num;//将num的绝对值赋给unumstr[i++]='-';//在字符串最前面设置为'-'号,并且索引加1}else unum=(unsigned)num;//若是num为正,直接赋值给unum//转换部分,注意转换后是逆序的do{str[i++]=index[unum%(unsigned)radix];//取unum的最后一位,并设置为str对应位,指示索引加1unum/=radix;//unum去掉最后一位}while(unum);//直至unum为0退出循环str[i]='\0';//在字符串最后添加'\0'字符,c语言字符串以'\0'结束。//将顺序调整过来if(str[0]=='-') k=1;//如果是负数,符号不用调整,从符号后面开始调整else k=0;//不是负数,全部都要调整char temp;//临时变量,交换两个值时用到for(j=k;j<=(i-1)/2;j++)//头尾一一对称交换,i其实就是字符串的长度,索引最大值比长度少1{temp=str[j];//头部赋值给临时变量str[j]=str[i-1+k-j];//尾部赋值给头部str[i-1+k-j]=temp;//将临时变量的值(其实就是之前的头部值)赋给尾部}return str;//返回转换后的字符串
}/**  str传入的数组基础地址,offset数组的偏移,c传入的字符*  返回填入字符后的偏移值*/
static uint8_t load_c(char *str,uint8_t offset ,char c)
{* (str + offset) = c;offset ++;return offset;
}
/**  str传入的数组基础地址,offset数组的偏移,data传入的数字*  返回填入字符后的偏移值*/
static uint8_t load_data(char *str,uint8_t offset ,uint32_t data)
{char datastr[17] = {0};itoa(data,datastr,10);uint8_t len = strlen(datastr);for(uint8_t i = 0 ; i < len ; i ++){* (str + offset) = datastr[i];offset ++;}return offset;
}
/**  str传入的数组基础地址,offset数组的偏移,data传入的数字*  返回填入字符后的偏移值*  与load_data不同的是,这个函数会吧数字保留一位小数装填*/
static uint8_t load_fdata(char *str,uint8_t offset ,uint32_t data)
{char datastr[17] = {0};itoa(data,datastr,10);uint8_t len = strlen(datastr);if(len == 1){* (str + offset++) = datastr[0]; * (str + offset++) = '.';* (str + offset++) = '0';}else if(len > 1){for(uint8_t i = 0 ; i < len ; i ++){* (str + offset++) = datastr[i];if( i == (len - 2))* (str + offset++)  = '.';}}return offset;
}/**  str传入的数组基础地址,offset数组的偏移,addstr传入的字符串*  返回填入字符后的偏移值*/
static uint8_t load_string(char *str,uint8_t offset ,char *addstr)
{uint8_t len = strlen(addstr);for(uint8_t i = 0 ; i < len ; i ++){* (str + offset) = addstr[i];offset ++;}return offset;}

my_printf函数试验

char a = 1;
char b = 21;
char str[20] = {0};
strcpy(str,"hello world!")
my_printf("a = %u , b = %f , str = %s" , a , b , str );
//输出结果 a = 1 , b = 2.1 ,str = hello world!

c语言 不定参数printf的实现相关推荐

  1. c语言int val,c语言不定参数与printf函数的实现

    今天学习了C语言不定参数,C语言中的不定参数主要靠这个头文件实现,这个头文件包含了va_list().va_start().va_end()三个宏,其用法为先声明一个va_list类型的变量,它用于访 ...

  2. c语言中代码参数太少,C语言不定参数探究

    一.可变参数函数原型 可变参数函数的原型声明格式为:type VAFunction(type arg1, type arg2, - ); 参数可以分为两部分:个数确定的固定参数和个数可变的可选参数.函 ...

  3. c语言不定参数个数,C语言中不定参数的实现

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 但是请注意,由於 K&R C 中并不检查参数型态,so 在此是用 ANSI C 来说明,毕竟 ANSI C 是目前所有 C Compiler 都支 ...

  4. c语言不定参数的使用,C语言中不定参数的实现

    该楼层疑似违规已被系统折叠 隐藏此楼查看此楼 但是请注意,由於 K&R C 中并不检查参数型态,so 在此是用 ANSI C 来说明,毕竟 ANSI C 是目前所有 C Compiler 都支 ...

  5. C语言———不定参数标准库 stdarg.h

    前言: 在很多工程代码中,工程师考虑到后续软件设计的兼容性和扩展性,在接口函数中时常会使用一些可变参数.一开始全部考虑到这些很难,因为统筹全局需要经验和思考来支撑.C语言标准库<stdarg.h ...

  6. c语言可变参数 printf,c语言 使用可变参数列表实现printf(my_printf)

    //使用可变参数列表实现print("s\t c\n","bit-tech",'w'); #include #include void int_to_char( ...

  7. C语言不定参数的作用,分享:C语言的三种不定参数,省略号用法

    1. #define log(...) log2(__VA_ARGS__) 2. #deinfe log(fmt...) log2(fmt) 3. #define log(fmt,...) log2( ...

  8. c语言设置制表符参数,printf()函数的参数和制表符

    · 参数 · 控制符 · 转义序列 printf("这是第们学习的第4课"); printf("12345\n6789"); \n  换行 \r  回车键 \b ...

  9. C语言可变参数函数(printf/scanf)

    C 语言允许定义参数数量可变的函数,这称为可变参数函数(variadic function).这种函数需要固定数量的强制参数(mandatory argument),后面是数量可变的可选参数(opti ...

最新文章

  1. Git 错误提交后该如何回滚操作
  2. 0基础学好python难不难_零基础学习Python难不难?Python有什么优势?
  3. 【高斯消元】[HDU 3359][POJ3999][UVALive4741]Kind of a Blur
  4. python 中文字符串截取,Python实现针对含中文字符串的截取功能示例
  5. sed命令 学习笔记
  6. 我的开发框架(WinForm)
  7. C语言中static关键字详解
  8. vs2013 提交 github
  9. 移动设备应用程序中支持多个屏幕大小和 DPI 值
  10. 【零基础学Java】—继承父类并实现多个接口(二十五)
  11. 设计模式(六) : 创建型模式--原型模式
  12. linux下驱动程序数字签名,64位Windows操作系统为驱动程序添加测试数字签名
  13. win10 系统Docker搭建设备共享平台stf(一)
  14. 阿里云ECS服务器实例是什么意思?关于实例的讲解
  15. 23万字 前端HTML与CSS学习笔记总结篇(超详细)
  16. 自定义数据集(Pokemon)实战
  17. Revit空闲事件(Idling Event)增强和外部事件(External Event)
  18. C语言编程>第二十五周 ① 给定程序中,函数fun的功能是:在形参s所指字符串中的每个非数字字符之后插入一个“*”号。
  19. C/C++图书信息管理系统水电管理信息系统
  20. Markdown语法(常用语法,快速掌握)

热门文章

  1. Blackhat 2012 USA 工具以及视频迅雷快传下载
  2. 解决:template might not exist or might not be accessible by any of the configured Template Resolvers报错
  3. PMP认证证书的实际作用!
  4. 【node.js错误1】Microsoft JScript运行时错误
  5. css在ios和安卓上的兼容问题(持续更新)
  6. [Asp.net mvc]实体更新异常:存储区更新、插入或删除语句影响到了意外的行数(0)。实体在加载后可能被修改或删除。
  7. 高校教材管理系统 数据库
  8. 北斗/GPS卫星时钟系统(北斗/GPS卫星授时系统-北斗/GPS卫星校时系统)
  9. 菜鸟 学注册机编写之 “查表”
  10. 原理图库元件符号之排针元件符号的创建