嵌入式操作系统---打印函数(printf/sprintf)的实现

2019-07-12 23:06发布

格式化输出函数:printf/sprintf/fprintf/snprintf等等 一、打印函数简介 作用:将“给定的内容”按照“指定的格式”输出到“指定目标内”。 打印函数的基本格式: char print_buf[BUF_SIZE]; void printf(const char *fmt, ...) { va_list ap;//定义一个指针变量 unsigned int i; va_start (ap, fmt); i = vsprintf (print_buf, sizeof(print_buf),fmt, ap); va_end (args); __put_char (print_buf,i); } printf(const char *fmt,...)是一个可变参数函数,第一个参数为字符串,后面是格式化输出参数列表。
c语言中函数的参数都是压进栈里的,可变参数函数必须有一个参数表示参数的个数,才能让编译器知道要压进栈多少参数,以及函数返回时弹出多少参数,printf(char *fmt,...)实现这个功能的是fmt字符串,里面有多少'%',就代表后面有多少个参数,所以我们必须提取出fmt字符串中'%'的个数,以及针对'%'后面不同的字符来处理参数。 const char *fmt定义了一个只读字符指针;“...”表示printf的参数是可变的; va_list ap:定义一个字符型指针变量 va_start(argv,i):初始化argv c=va_arg(argv,int):在已知变量的情况下,获得下一个变参变量 va_end(argv):结束变参变量操作 其中,__put_char()将字符逐个打印到串口输出寄存器中。 void __put_char(char *p,int num){
while(*p&&num--){
*(volatile unsigned int *)0xd0000020=*p++;
};
} 二、打印函数的实现 1、变参函数的实现(宏定义) (1)va_list typedef char * va_list; va_list ap; //定义一个指针类型 (2)va_start(ap,fmt)  #define va_start(ap,fmt) ( ap = (va_list)&fmt + _INTSIZEOF(fmt) ) ap指向函数栈中变参列表第一个参数的首地址; ____________________________
|___________________________|
|                      argn                              |
|                      ........                              |
|                      arg0                              |<----ap(sizeof(int)大小对齐)
|                      fmt                                 |
|                      pc                                  |
|___________________________| 注意:传给宏va_start的参数fmt是可变参数列表中的前一个参数,ap指向变参列表中第一个参数地址。
注意:函数参数压栈时,参数的入栈顺序是从右向左,出栈时是从左向右。函数调用时,先把若干个参数都压入栈中,再压fmt,最后压pc,这样一来,栈顶指针偏移便找到了fmt,通过fmt中的%占位符,取得后面参数的个数,从而正确取得所有参数。 #define _INTSIZEOF(n) ((sizeof(n)+sizeof(int)-1)&~(sizeof(int) - 1) ) 计算int类型按4字节(int占4字节)对齐后的结果。通过使用_INTSIZEOF(n),可以根据一个变量的类型计算变量在内存中占用的字节数,从而正确定位参数在内存的位置。 对于short、char类型的数据,因为不满一个int类型的内存空间,所以按照int类型对齐; (3)va_arg(ap,type) #define va_arg(ap,type) ( *(type *)((ap += _INTSIZEOF(type)) - _INTSIZEOF(type)) ) 指针变量ap本身指向变参列表中的下一个参数地址,va_arg取出的是当前参数的值 (4)va_end(ap) #define va_end(ap) ( ap = (va_list)0 ) ap指向空   2、vsprintf(char *buf, const char *fmt, va_list args)函数实现 函数功能:将变量列表args中的参数按照fmt中规定的格式保存到临时缓存buf中。 int vsprintf(char *buf, canst char *fmt, va_list args) { unsigned NUM_TYPE num; int base; char*str; int flags; int field_width; int Precision; int qualifier; str = bUf; for (; *fmt ; ++fmt) { if (* fmt ! = ' % ' ) { *str++ = *fmt; continue; } /* process flags */ flags = 0; repeat: ++fmt;/* skip first "%" */ switch(*fmt) { case '- ' : flags |= LEFT;goto repeat; case '+ ' : flags |= PLUS;goto repeat; ... } ... base = 10; switch (*fmt){ case 'c': ... *str++ (unsigned char)va_arg(args,int); ... continue; case 's': str = string(str,va_arg(args, char *),field_width,precision,flags); continue; ... case ' X ' : base = 16; break; case 'd': case ' i ' flags |= SIGN; case 'u': break; default: * str++ ='%'; if (*fmt) *str++ = *fmt; else --fmt ; continue; } str = number (str, num, base, field_width, precision, flags) ; } *str == '