亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频

? 歡迎來到蟲蟲下載站! | ?? 資源下載 ?? 資源專輯 ?? 關(guān)于我們
? 蟲蟲下載站

?? printf

?? uC/OS-II在51上移植的完整源代碼V1.0
??
?? 第 1 頁 / 共 2 頁
字號:
                                     printf在uCOS51上的移植和浮點數(shù)顯示
                                      asdjf@163.com   2003/10/20
                                      

    printf函數(shù)是C語言里應(yīng)用最為廣泛的函數(shù)之一,我們初學(xué)C語言時實現(xiàn)的第一個程序《Hello the world》,就包含printf語句。它的應(yīng)用十分靈活,可以打印各種類型數(shù)據(jù),可變數(shù)量的變量,表達式,是非常理想的輸出函數(shù),廣泛用于結(jié)果輸出,中間變量顯示,調(diào)試等。然而,編譯器將其作為標準庫函數(shù),不提供源代碼,其本身代碼量也偏大,無法實現(xiàn)嵌入式系統(tǒng)按需裁減的要求,并且有些printf庫代碼不支持重入。
    解決方法是把Linux里的相關(guān)源碼簡化后移植到C51里。關(guān)鍵點在于理解變參函數(shù)、參數(shù)傳遞規(guī)則、浮點數(shù)存儲格式。
    C編譯器一般將函數(shù)參數(shù)按從右至左的順序依次壓入堆棧(C51在使用reentrant關(guān)鍵字后也這么處理),函數(shù)內(nèi)部處理參數(shù)變量時直接在堆棧上尋址,局部變量緊跟在參數(shù)后面存放,函數(shù)返回時出棧,參數(shù)和局部變量所占用空間自動釋放。例如:
    fun(char *fmt,char a,int b long c,float d) reentrant
    的堆棧結(jié)構(gòu)如圖1所示:
    
        ------------------
        |float d 4 bytes |
    +10 ------------------
        |long c 4 bytes  |
    +6  ------------------
        |int b 2 bytes   |
    +4  ------------------
        |char a 1 bytes  |
    +3  ------------------
        |char *fmt 3bytes|
 SP+0-->------------------
        |     局部變量    |
        ------------------
        圖1.fun函數(shù)參數(shù)和局部變量在堆棧里的結(jié)構(gòu)
    
    C51編譯器從右向左依次將float/long/int/char/char *壓入仿真堆棧,各種數(shù)據(jù)類型所占空間大小如圖1,例如char占1字節(jié),float占4字節(jié)等。值得一提的是,常數(shù)壓棧的格式:0-255按1字節(jié)壓棧,256-32767壓成2字節(jié),32768(8000H)或以上壓成4字節(jié),帶有l(wèi)/L結(jié)尾的常數(shù)占4字節(jié)。
    上面的函數(shù)fun內(nèi)部可以通過函數(shù)名稱訪問各個變量,C編譯器自動把函數(shù)名轉(zhuǎn)換成地址,如:訪問long c轉(zhuǎn)換成訪問SP+6,訪問char a轉(zhuǎn)換成訪問SP+3等。寫成表達式為:
    c=0x12345678;======>(SP+6)=0x12345678
    a='y';=============>(SP+3)='y'
    總之,上面的函數(shù)通過顯式地指定函數(shù)名和數(shù)據(jù)類型完成參數(shù)的傳遞和訪問,內(nèi)部細節(jié)由C編譯器完成,對用戶透明。
    這種方式的好處是表達清晰,結(jié)構(gòu)嚴謹,屏蔽底層細節(jié);壞處是不夠靈活,參數(shù)必須在處理前顯式確定并固定不變,這給我們用同一函數(shù)處理不同情況帶來了困難,C的解決方案是引入“變參函數(shù)”(詳見C語言大全),如下:
    fun(char *fmt,...) reentrant
    ...表示有0到N個可變數(shù)量參數(shù),C編譯器此時不檢查參數(shù)匹配,傳遞參數(shù)規(guī)律與一般函數(shù)相同。如果我們用這個函數(shù)取代前一個函數(shù),但仍按前一函數(shù)的調(diào)用方式調(diào)用,那么,參數(shù)在堆棧里的位置仍如圖1所示。此時,函數(shù)形參只有“...”沒有具體變量名,如何引用形參變量呢?觀察圖1堆棧結(jié)構(gòu)可知,如果知道堆棧內(nèi)第一個參數(shù)的起址和每個參數(shù)的數(shù)據(jù)類型及他們的排列順序,就可以通過指針訪問指定的變量。例如:
    知道堆棧內(nèi)第一個參數(shù)的起址SP和每個參數(shù)的數(shù)據(jù)類型及排列順序(char*/char/int/long/float),就可以通過SP,SP+3,SP+4,SP+6,SP+10訪問原來必須通過參數(shù)名訪問的fmt,a,b,c,d變量。寫成C語言就是:
    
    fun("yy",'y',(int)2,5L,-12.5);
    
    fun(char *fmt,...) reentrant
    {
    void *p;
    
    p=&fmt;
    //此時*p指向字符串"yy"首址,**p是字符串第一個字符'y'。
    p=(char **)p+1;
    //此時*((char *)p)為字符'y'。
    p=(char *)p+1;
    //此時*((int *)p)為0x0002。
    p=(int *)p+1;
    //此時*((long *)p)為0xC1480000,即-12.5的IEEE-754標準格式。
    p=(float *)p+1;
    }
    測試代碼:
void fun(char *fmt,...) reentrant
{
  void *p;

  p=&fmt;
  PrintChar(**((char **)p));
  p=((char **)p) +1;
  PrintChar(*((char *)p));
  p=((char *)p) +1;
  PrintLong(*((int *)p));
  p=((int *)p) +1;
  PrintLong(*((long *)p));
  p=((long *)p) +1;
  PrintLong(*((long *)p));
  p=((float *)p) +1;
}
    顯示結(jié)果:yy0000000200000005C1480000
    由上面知,在C里不用顯式使用SP等堆棧指針,而是使用void指針指向各種類型數(shù)據(jù)。變參函數(shù)的參數(shù)傳遞和獲取就是這樣運做的,知道了它的原理,就不難理解printf的實現(xiàn)了。
    我所移植的printf支持標準或長二進制/八進制/十進制/十六進制/無符號整數(shù),支持字符、字符串、浮點數(shù)、百分號%顯示。其中,浮點數(shù)在整個范圍內(nèi)被完全支持,統(tǒng)一采用科學(xué)記數(shù)法顯示。對應(yīng)的指示符如下:
    c 字符    f 浮點數(shù)    s 字符串    % 百分號顯示
    d/ld 2字節(jié)/4字節(jié)有符號整數(shù)    u/lu 2字節(jié)/4字節(jié)無符號整數(shù)
    x/lx 2字節(jié)/4字節(jié)十六進制數(shù)    o/lo 2字節(jié)/4字節(jié)八進制數(shù)
    b/lb 2字節(jié)/4字節(jié)二進制數(shù)
    
    printf的功能是字符串化數(shù)據(jù),它的第一個參數(shù)是格式化字符串fmt,用其指示第一個參數(shù)在堆棧里的起址和其后各個參數(shù)的數(shù)據(jù)類型。知道了參數(shù)堆棧起址和各個參數(shù)的類型和排放次序,就可以依次取出各個參數(shù)并字符串化。詳細過程參見yyprintf源代碼。同時,注意到參數(shù)是依靠起址和數(shù)據(jù)長度信息依次讀出來的,那么,yyprintf的參數(shù)必須與格式化參數(shù)的指示相同,否則參數(shù)數(shù)據(jù)會亂掉。對于不能肯定的轉(zhuǎn)化數(shù)據(jù)類型建議加上強制類型定義,如(int) 2。特別是常數(shù)的轉(zhuǎn)換類型容易搞錯。
    printf大部分代碼與硬件無關(guān),只有參數(shù)堆棧結(jié)構(gòu)和打印一個字符putchar()函數(shù)是硬件相關(guān)的。移植printf時只要修改putchar()函數(shù)和堆棧結(jié)構(gòu)即可。putchar()函數(shù)的功能一般是向串口輸出一個字符,也可以向其他顯示設(shè)備輸出一個字符,取決于你的驅(qū)動程序。我已經(jīng)在uCOS51里實現(xiàn)了PrintChar函數(shù),直接調(diào)用就可以了。其實,在X86、POWERPC、ARM等32位CPU上移植printf更加有效和方便。
    
    測試舉例:
    float r=1.9835671E-10,pi=3.1415926;
    yyprintf("R=%f  Circle area=%f\n",r,pi*r*r);
    結(jié)果:
    R=1.983567E-10  Circle area=1.236071E-19
        
    源代碼:
//============================================================================================
//
//============================================================================================
void yyprintf(char *fmt,...) reentrant  //自編簡單printf等效函數(shù)
{
    void *p;  //任意指針,可以指向任何類型,C語法不對其嚴格要求。
    char ch;
    unsigned char j;

    p=&fmt;
    p=(char **)p+1;  //此處p是指向指針的指針,fmt是字符串指針,p是指向fmt的指針

    while(1){
        while((ch=*fmt++)!='%'){
            if(ch=='\0') return;
            else if(ch=='\n'){PrintChar(10);PrintChar(13);}
            else if(ch=='\t'){
                for(j=0;j<TABNum;j++)
                    PrintChar(' ');
            }
            else PrintChar(ch);
        }
        ch=*fmt++;
        switch(ch){
            case 'c':
                PrintChar(*((char *)p));
                p=(char *)p+1;
                break;
            case 'd':
                PrintN(*((int *)p),10);
                p=(int *)p+1;
                break;
            case 'x':
                PrintN(*((int *)p),16);
                p=(int *)p+1;
                break;
            case 'o':
                PrintUN(*((int *)p),8);
                p=(int *)p+1;
                break;
            case 'b':
                PrintUN(*((int *)p),2);
                p=(int *)p+1;
                break;
            case 'l':
                ch=*fmt++;
                switch(ch){
                    case 'd':
                        PrintLN(*((long *)p),10);
                        p=(long *)p+1;
                        break;
                    case 'o':
                        PrintLUN(*((long *)p),8);
                        p=(long *)p+1;
                        break;
                    case 'u':
                        PrintLUN(*((unsigned long *)p),10);
                        p=(unsigned long *)p+1;
                        break;
                    case 'b':
                        PrintLUN(*((long *)p),2);
                        p=(long *)p+1;
                        break;
                    case 'x':
                        PrintLN(*((long *)p),16);
                        p=(long *)p+1;
                        break;
                    default:
                        return;
                }
                break;
            case 'f':
                DispF(*((float *)p));
                p=(float *)p+1;
                break;
            case 'u':
                PrintUN(*((unsigned int *)p),10);
                p=(unsigned int *)p+1;
                break;
            case 's':
                PrintStr(*((char **)p));
                p=(char **)p+1;
                break;
            case '%':
                PrintChar('%');
                p=(char *)p+1;
                break;
            default:
                return;
        }
    }
}

void PrintN(int n,int b) reentrant  //十進制顯示整形數(shù)
{
    if(b==16){PrintWord(n);return;}
	if(n<0){PrintChar('-');n=-n;}
	if(n/b)
	    PrintN(n/b,b);
	PrintChar(n%b+'0');
}

void PrintUN(unsigned int n,unsigned int b) reentrant  //十進制顯示無符號整形數(shù)
{
    if(b==16){PrintWord(n);return;}
	if(n/b)
	    PrintUN(n/b,b);
	PrintChar(n%b+'0');
}


void PrintLN(long n,long b) reentrant  //十進制顯示長整形數(shù)
{
    if(b==16){PrintLong(n);return;}
	if(n<0){PrintChar('-');n=-n;}
	if(n/b)
	    PrintLN(n/b,b);
	PrintChar(n%b+'0');
}

void PrintLUN(unsigned long n,unsigned long b) reentrant  //十進制顯示無符號長整形數(shù)
{
    if(b==16){PrintLong(n);return;}
	if(n/b)
	    PrintLUN(n/b,b);
	PrintChar(n%b+'0');
}

參考文獻:

1。《ROM版本下系統(tǒng)調(diào)試信息的一種顯示方法》合肥工業(yè)大學(xué) 彭良清 《單片機與嵌入式系統(tǒng)應(yīng)用》p22頁2002(1-6)


TO BE CONTINUED...


                                浮點數(shù)顯示

?? 快捷鍵說明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號 Ctrl + =
減小字號 Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
色av综合在线| 视频一区欧美精品| 一区二区激情视频| 水野朝阳av一区二区三区| 日av在线不卡| 国产精品影视在线观看| 成人黄色av网站在线| 欧美性色黄大片手机版| 欧美成人精品福利| 国产精品久久福利| 日本视频中文字幕一区二区三区| 国产一区二区网址| 色av综合在线| 久久综合精品国产一区二区三区| 亚洲人成在线观看一区二区| 免费在线观看成人| 91视频一区二区| 日韩欧美一二三| 亚洲视频一区在线观看| 欧美aaaaaa午夜精品| av中文字幕亚洲| 日韩一级完整毛片| 亚洲色图视频网| 韩国午夜理伦三级不卡影院| 91网站最新网址| 久久综合色鬼综合色| 一区二区三区在线免费播放| 久久99精品久久久久久| 91天堂素人约啪| 久久久久久久久久美女| 亚洲第一福利一区| 成人午夜免费电影| 日韩一区二区三区精品视频| 日韩一区在线免费观看| 久久 天天综合| 欧美日韩高清一区二区三区| 国产偷v国产偷v亚洲高清| 天堂在线亚洲视频| 一本一道久久a久久精品| 久久久久国产精品麻豆| 亚洲成a人v欧美综合天堂下载| 国产成人精品午夜视频免费 | 亚洲激情图片qvod| 国产专区欧美精品| 欧美一区中文字幕| 夜夜嗨av一区二区三区中文字幕| 国产福利一区在线| 欧美大片一区二区| 午夜精品一区在线观看| 色综合久久88色综合天天| 国产日本欧洲亚洲| 国产乱国产乱300精品| 欧美日韩一区三区| 亚洲一区二区在线播放相泽| bt7086福利一区国产| 国产欧美精品一区二区色综合| 久久精品72免费观看| 在线91免费看| 亚洲mv在线观看| 欧美午夜电影在线播放| 亚洲激情在线激情| 91视频你懂的| 亚洲欧美韩国综合色| 成人午夜视频网站| 国产精品色噜噜| 福利一区二区在线| 国产亚洲一区二区三区在线观看| 国内精品自线一区二区三区视频| 日韩免费一区二区| 理论电影国产精品| 日韩亚洲国产中文字幕欧美| 青青草国产成人av片免费| 91麻豆精品国产| 日韩在线一区二区| 欧美一区三区四区| 美洲天堂一区二卡三卡四卡视频| 91精品国产入口在线| 免费观看成人av| 精品国产亚洲一区二区三区在线观看 | 久久99精品久久久久婷婷| 欧美大片一区二区三区| 国产一区二区三区免费看| 久久久久久久久久久黄色| 国产99一区视频免费| 国产精品天天看| 99久久国产综合精品女不卡| 亚洲另类色综合网站| 欧美午夜精品久久久久久超碰| 天堂va蜜桃一区二区三区漫画版| 欧美一区二区三区四区视频| 国产在线精品国自产拍免费| 国产精品美女视频| 色噜噜久久综合| 五月天欧美精品| 欧美mv和日韩mv的网站| 国产精品一卡二| 亚洲九九爱视频| 在线综合+亚洲+欧美中文字幕| 老司机免费视频一区二区三区| 国产蜜臀av在线一区二区三区| aaa国产一区| 天天综合天天做天天综合| 久久伊99综合婷婷久久伊| 99精品视频在线播放观看| 亚洲精品大片www| 日韩一区二区精品| 成人国产在线观看| 亚洲 欧美综合在线网络| 精品国产免费视频| 日本韩国精品一区二区在线观看| 午夜精品福利一区二区蜜股av| 337p日本欧洲亚洲大胆精品| 99麻豆久久久国产精品免费| 亚洲v日本v欧美v久久精品| 久久综合色综合88| 欧洲生活片亚洲生活在线观看| 日韩高清国产一区在线| 日本一区二区成人| 欧美日韩视频第一区| 国产不卡高清在线观看视频| 亚洲一区二区三区小说| 久久精品一区二区三区不卡| 欧亚洲嫩模精品一区三区| 精品一区二区三区免费视频| 亚洲欧美一区二区三区极速播放| 日韩视频免费观看高清完整版在线观看| 国产成人av电影在线观看| 亚洲最快最全在线视频| 国产视频一区二区在线观看| 欧美优质美女网站| 国产91丝袜在线播放九色| 五月婷婷综合在线| 国产精品美女久久久久高潮| 91精品午夜视频| 99国产精品99久久久久久| 精品一区在线看| 亚洲午夜免费视频| 国产精品毛片久久久久久久 | 蜜桃免费网站一区二区三区| 亚洲欧美在线观看| 久久夜色精品一区| 欧美乱妇23p| 99久久精品免费看国产| 精油按摩中文字幕久久| 一区二区三区美女视频| 中文字幕+乱码+中文字幕一区| 日韩亚洲欧美高清| 欧美日韩三级一区| 91热门视频在线观看| 国产精品白丝av| 美女看a上一区| 首页国产丝袜综合| 亚洲精品少妇30p| 国产曰批免费观看久久久| 日精品一区二区三区| 尤物视频一区二区| 中文字幕在线观看一区二区| 久久香蕉国产线看观看99| 欧美高清激情brazzers| 色视频一区二区| jvid福利写真一区二区三区| 国产综合成人久久大片91| 日韩精品欧美成人高清一区二区| 亚洲日本va午夜在线电影| 欧美国产视频在线| 国产午夜精品美女毛片视频| 精品美女一区二区| 日韩欧美中文字幕公布| 欧美一区二区在线免费观看| 欧美色图激情小说| 在线观看国产一区二区| 色综合久久久久网| 色一区在线观看| av一区二区三区黑人| 成人精品一区二区三区中文字幕| 精品亚洲欧美一区| 国产真实乱子伦精品视频| 极品少妇一区二区三区精品视频| 日本aⅴ亚洲精品中文乱码| 五月激情丁香一区二区三区| 性欧美大战久久久久久久久| 亚洲成人自拍网| 日日摸夜夜添夜夜添国产精品 | 在线观看日韩精品| 色婷婷综合久久久久中文| 成人黄页毛片网站| 97久久超碰精品国产| 91亚洲精品一区二区乱码| 91蝌蚪porny九色| 91蜜桃婷婷狠狠久久综合9色| 色综合夜色一区| 色综合久久88色综合天天6| 欧美综合在线视频| 777午夜精品视频在线播放| 欧美一级片免费看| 久久夜色精品一区| 中文字幕一区二区三区在线播放 | av网站一区二区三区| 94-欧美-setu| 欧美性淫爽ww久久久久无|