首先从网上找到了glibc的标准库的内容,找到了里面的printf.c的函数实现
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
return done;
*(p_buffer++) = *(p_string++);
counter++;
}
int
__printf (const char *format, ...)
{
}
以前一直没有仔细看这个函数,她的返回值是一个整型,(其实就是返回成功在现实屏上输出的字符个数);她带有。。。额。。。不知道该说几个参数,第一个参数是一个字符串类型的指针常量(相当于一个数组的开头),然后是省略号...;这是变参的表示方法,表示我们具体有几个参数不确定,参数的个数是由第一个参数决定的(即第一个参数里面的内容可以决定后面一共有几个参数);
然后是
va_list arg;这一句,包含在头文件里面,这是一种变参列表的类型,可以用来保存字符串中的字符和变量之间的关系
接下来是
va_start (arg, format);
done = vfprintf (stdout, format, arg);
va_end (arg);
其中
va_start (arg, format);是把字符串format里面的内容提取参数到arg变参列表里面
done = vfprintf (stdout, format, arg);这里是调用另外一个现实函数vsprintf,把arg包含变参列表的内容以format格式输出到stdout(标准输出,PC上默认是电脑屏幕)
va_end (arg);结束转化
这是标准库里的实现,但是我们才使用嵌入式的时候还可以做一些改动,把标注输出到屏幕改成输出到UART串口上;
为了避免移植的时候要包括很多不知道的函数和头文件(一个没有包含就会出错,相互调用的太多了),所以就参考了网上以为大牛的博客,他是自己写了一个pritnf函数,亲测在linux ubuntu 15.10下可用
先贴上他的代码(其中我加了点注释和对效果的检查)
#include
#include
int my_printf(const char* string,...);
int main()
{
int x;
my_printf("the x is :%d\n", x);
my_printf("hello world!\n");
return 0;
}
int my_printf(const char* string,...)
{
char buffer[BUFSIZ];//Be tolerant with my_printf, never try to jump ovet the band of the buffer -- buffer overflow
int temp = 0;
va_list arg;
char* p_string = NULL;
char* p_buffer = buffer;
char* p_temp
= NULL;
int counter = 0; //the value is to return the numbers of the characters put into the 'puts' succeessfully (can be ignored)
int number
= 0;
int foo
= 0;
va_start(arg,string);
for(counter = 0,p_string = string;*(p_string) != '\0';)
{
switch(*p_string)
{
case '%':
p_string++;
switch(*p_string)
{
case 'd': //the value is a number
temp = va_arg(arg,int);
foo = temp;
while(foo)
{
number++;
counter++;
foo /= 10;
}
foo = temp;
while(number)
{
*(p_buffer+number-1) = (foo);
foo /= 10;
number--;
}
p_buffer += number;
break;
case 'c': //the value is a character
temp = va_arg(arg,int);
*(p_buffer++) = temp;
break;
case 's': //the value is a string of characters
p_temp = va_arg(arg,char*);
while(p_temp != NULL)
{
*(p_buffer++) = *(p_temp++);
counter++;
}
break;
default:
break;
}
break;
default:
}
va_end(arg);
p_buffer = NULL;
puts(buffer);
return counter;
}
下面说说具体思路,同标准库的printf,首先进行参数列表的提取,然后判断接下来的字符是否代表参数,如果是参数则改变原来的字符串,判断完整个字符串后(字符串长度可能会改变),则结束参量转换,最后把得到的 新的字符串用其它方式输出,比如可以用串口,或者其它的print显示函数。