printf的學習
首先從網上找到了glibc的標準庫的內容,找到了裏面的printf.c的函數實現
int
__printf (const char *format, ...)
{
va_list arg;
int done;
va_start (arg, format);
done = vfprintf (stdout, format,
arg);
va_end (arg);
return done;
}
以前一直沒有仔細看這個函數,她的返回值是一個整型,(其實就是返回成功在現實屏上輸出的字符個數);她帶有。。。額。。。不知道該說幾個參數,第一個參數是一個字符串類型的指針常量(相當於一個數組的開頭),然後是省略號...;這是變參的表示方法,表示我們具體有幾個參數不確定,參數的個數是由第一個參數決定的(即第一個參數裏面的內容可以決定後面一共有幾個參數);
然後是 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:
*(p_buffer++) = *(p_string++);
counter++;
}
}
va_end(arg);
p_buffer = NULL;
puts(buffer);
return counter;
}
下面說說具體思路,同標準庫的printf,首先進行參數列表的提取,然後判斷接下來的字符是否代表參數,如果是參數則改變原來的字符串,判斷完整個字符串後(字符串長度可能會改變),則結束參量轉換,最後把得到的
新的字符串用其它方式輸出,比如可以用串口,或者其它的print顯示函數。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.