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

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

?? printf

?? ucos 51 tcp/ip開發(fā)文檔
??
?? 第 1 頁(yè) / 共 2 頁(yè)
字號(hào):
                                     printf在uCOS51上的移植和浮點(diǎn)數(shù)顯示
                                      asdjf@163.com   2003/10/20
                                      

    printf函數(shù)是C語(yǔ)言里應(yīng)用最為廣泛的函數(shù)之一,我們初學(xué)C語(yǔ)言時(shí)實(shí)現(xiàn)的第一個(gè)程序《Hello the world》,就包含printf語(yǔ)句。它的應(yīng)用十分靈活,可以打印各種類型數(shù)據(jù),可變數(shù)量的變量,表達(dá)式,是非常理想的輸出函數(shù),廣泛用于結(jié)果輸出,中間變量顯示,調(diào)試等。然而,編譯器將其作為標(biāo)準(zhǔn)庫(kù)函數(shù),不提供源代碼,其本身代碼量也偏大,無(wú)法實(shí)現(xiàn)嵌入式系統(tǒng)按需裁減的要求,并且有些printf庫(kù)代碼不支持重入。
    解決方法是把Linux里的相關(guān)源碼簡(jiǎn)化后移植到C51里。關(guān)鍵點(diǎn)在于理解變參函數(shù)、參數(shù)傳遞規(guī)則、浮點(diǎn)數(shù)存儲(chǔ)格式。
    C編譯器一般將函數(shù)參數(shù)按從右至左的順序依次壓入堆棧(C51在使用reentrant關(guān)鍵字后也這么處理),函數(shù)內(nèi)部處理參數(shù)變量時(shí)直接在堆棧上尋址,局部變量緊跟在參數(shù)后面存放,函數(shù)返回時(shí)出棧,參數(shù)和局部變量所占用空間自動(dòng)釋放。例如:
    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)部可以通過(guò)函數(shù)名稱訪問(wèn)各個(gè)變量,C編譯器自動(dòng)把函數(shù)名轉(zhuǎn)換成地址,如:訪問(wèn)long c轉(zhuǎn)換成訪問(wèn)SP+6,訪問(wèn)char a轉(zhuǎn)換成訪問(wèn)SP+3等。寫成表達(dá)式為:
    c=0x12345678;======>(SP+6)=0x12345678
    a='y';=============>(SP+3)='y'
    總之,上面的函數(shù)通過(guò)顯式地指定函數(shù)名和數(shù)據(jù)類型完成參數(shù)的傳遞和訪問(wèn),內(nèi)部細(xì)節(jié)由C編譯器完成,對(duì)用戶透明。
    這種方式的好處是表達(dá)清晰,結(jié)構(gòu)嚴(yán)謹(jǐn),屏蔽底層細(xì)節(jié);壞處是不夠靈活,參數(shù)必須在處理前顯式確定并固定不變,這給我們用同一函數(shù)處理不同情況帶來(lái)了困難,C的解決方案是引入“變參函數(shù)”(詳見C語(yǔ)言大全),如下:
    fun(char *fmt,...) reentrant
    ...表示有0到N個(gè)可變數(shù)量參數(shù),C編譯器此時(shí)不檢查參數(shù)匹配,傳遞參數(shù)規(guī)律與一般函數(shù)相同。如果我們用這個(gè)函數(shù)取代前一個(gè)函數(shù),但仍按前一函數(shù)的調(diào)用方式調(diào)用,那么,參數(shù)在堆棧里的位置仍如圖1所示。此時(shí),函數(shù)形參只有“...”沒(méi)有具體變量名,如何引用形參變量呢?觀察圖1堆棧結(jié)構(gòu)可知,如果知道堆棧內(nèi)第一個(gè)參數(shù)的起址和每個(gè)參數(shù)的數(shù)據(jù)類型及他們的排列順序,就可以通過(guò)指針訪問(wèn)指定的變量。例如:
    知道堆棧內(nèi)第一個(gè)參數(shù)的起址SP和每個(gè)參數(shù)的數(shù)據(jù)類型及排列順序(char*/char/int/long/float),就可以通過(guò)SP,SP+3,SP+4,SP+6,SP+10訪問(wèn)原來(lái)必須通過(guò)參數(shù)名訪問(wèn)的fmt,a,b,c,d變量。寫成C語(yǔ)言就是:
    
    fun("yy",'y',(int)2,5L,-12.5);
    
    fun(char *fmt,...) reentrant
    {
    void *p;
    
    p=&fmt;
    //此時(shí)*p指向字符串"yy"首址,**p是字符串第一個(gè)字符'y'。
    p=(char **)p+1;
    //此時(shí)*((char *)p)為字符'y'。
    p=(char *)p+1;
    //此時(shí)*((int *)p)為0x0002。
    p=(int *)p+1;
    //此時(shí)*((long *)p)為0xC1480000,即-12.5的IEEE-754標(biāo)準(zhǔn)格式。
    p=(float *)p+1;
    }
    測(cè)試代碼:
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ù)傳遞和獲取就是這樣運(yùn)做的,知道了它的原理,就不難理解printf的實(shí)現(xiàn)了。
    我所移植的printf支持標(biāo)準(zhǔn)或長(zhǎng)二進(jìn)制/八進(jìn)制/十進(jìn)制/十六進(jìn)制/無(wú)符號(hào)整數(shù),支持字符、字符串、浮點(diǎn)數(shù)、百分號(hào)%顯示。其中,浮點(diǎn)數(shù)在整個(gè)范圍內(nèi)被完全支持,統(tǒng)一采用科學(xué)記數(shù)法顯示。對(duì)應(yīng)的指示符如下:
    c 字符    f 浮點(diǎn)數(shù)    s 字符串    % 百分號(hào)顯示
    d/ld 2字節(jié)/4字節(jié)有符號(hào)整數(shù)    u/lu 2字節(jié)/4字節(jié)無(wú)符號(hào)整數(shù)
    x/lx 2字節(jié)/4字節(jié)十六進(jìn)制數(shù)    o/lo 2字節(jié)/4字節(jié)八進(jìn)制數(shù)
    b/lb 2字節(jié)/4字節(jié)二進(jìn)制數(shù)
    
    printf的功能是字符串化數(shù)據(jù),它的第一個(gè)參數(shù)是格式化字符串fmt,用其指示第一個(gè)參數(shù)在堆棧里的起址和其后各個(gè)參數(shù)的數(shù)據(jù)類型。知道了參數(shù)堆棧起址和各個(gè)參數(shù)的類型和排放次序,就可以依次取出各個(gè)參數(shù)并字符串化。詳細(xì)過(guò)程參見yyprintf源代碼。同時(shí),注意到參數(shù)是依靠起址和數(shù)據(jù)長(zhǎng)度信息依次讀出來(lái)的,那么,yyprintf的參數(shù)必須與格式化參數(shù)的指示相同,否則參數(shù)數(shù)據(jù)會(huì)亂掉。對(duì)于不能肯定的轉(zhuǎn)化數(shù)據(jù)類型建議加上強(qiáng)制類型定義,如(int) 2。特別是常數(shù)的轉(zhuǎn)換類型容易搞錯(cuò)。
    printf大部分代碼與硬件無(wú)關(guān),只有參數(shù)堆棧結(jié)構(gòu)和打印一個(gè)字符putchar()函數(shù)是硬件相關(guān)的。移植printf時(shí)只要修改putchar()函數(shù)和堆棧結(jié)構(gòu)即可。putchar()函數(shù)的功能一般是向串口輸出一個(gè)字符,也可以向其他顯示設(shè)備輸出一個(gè)字符,取決于你的驅(qū)動(dòng)程序。我已經(jīng)在uCOS51里實(shí)現(xiàn)了PrintChar函數(shù),直接調(diào)用就可以了。其實(shí),在X86、POWERPC、ARM等32位CPU上移植printf更加有效和方便。
    
    測(cè)試舉例:
    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  //自編簡(jiǎn)單printf等效函數(shù)
{
    void *p;  //任意指針,可以指向任何類型,C語(yǔ)法不對(duì)其嚴(yán)格要求。
    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  //十進(jìn)制顯示整形數(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  //十進(jìn)制顯示無(wú)符號(hào)整形數(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  //十進(jìn)制顯示長(zhǎng)整形數(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  //十進(jìn)制顯示無(wú)符號(hào)長(zhǎng)整形數(shù)
{
    if(b==16){PrintLong(n);return;}
	if(n/b)
	    PrintLUN(n/b,b);
	PrintChar(n%b+'0');
}

參考文獻(xiàn):

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


TO BE CONTINUED...


                                浮點(diǎn)數(shù)顯示

?? 快捷鍵說(shuō)明

復(fù)制代碼 Ctrl + C
搜索代碼 Ctrl + F
全屏模式 F11
切換主題 Ctrl + Shift + D
顯示快捷鍵 ?
增大字號(hào) Ctrl + =
減小字號(hào) Ctrl + -
亚洲欧美第一页_禁久久精品乱码_粉嫩av一区二区三区免费野_久草精品视频
亚洲国产裸拍裸体视频在线观看乱了| 日韩区在线观看| 首页综合国产亚洲丝袜| 久久先锋资源网| 欧美日韩二区三区| 成人免费av在线| 久久精品国产亚洲a| 亚洲激情在线激情| 国产精品理论片| 精品美女一区二区三区| 欧洲一区二区三区免费视频| 懂色一区二区三区免费观看| 蜜桃精品在线观看| 亚洲午夜久久久久中文字幕久| 欧美激情一区在线| 精品国产免费视频| 欧美一级黄色大片| 欧美日韩中文另类| 色婷婷久久一区二区三区麻豆| 国产成人在线免费观看| 麻豆精品一区二区av白丝在线| 一区二区三区国产| 亚洲男人的天堂av| 中文字幕五月欧美| 国产日韩欧美激情| 久久精品夜夜夜夜久久| 日韩欧美中文字幕一区| 777欧美精品| 在线观看91精品国产麻豆| 91官网在线观看| 在线视频观看一区| 色婷婷av一区二区三区之一色屋| 播五月开心婷婷综合| 国产激情一区二区三区| 国产真实乱偷精品视频免| 亚洲国产欧美另类丝袜| 亚洲一区二区在线免费看| 亚洲三级在线免费| 亚洲一区在线播放| 亚洲一区二区三区中文字幕在线| 一区二区三区欧美| 亚洲综合一区二区三区| 亚洲综合清纯丝袜自拍| 亚洲一区二区三区在线播放| 午夜一区二区三区视频| 亚洲国产精品久久不卡毛片| 婷婷久久综合九色综合绿巨人| 亚洲成人激情av| 日韩av一级电影| 久久99精品国产.久久久久| 国产一区啦啦啦在线观看| 国产乱淫av一区二区三区| 国产精品一区二区无线| 成人激情午夜影院| 欧美在线观看一二区| 欧美猛男男办公室激情| 欧美成人a∨高清免费观看| 欧美α欧美αv大片| 国产色综合一区| 亚洲视频一区二区在线| 亚洲成av人片在线观看无码| 免费在线观看精品| 懂色一区二区三区免费观看| 91麻豆免费看| 91精品在线免费观看| 精品国产区一区| 18成人在线视频| 亚洲成人动漫精品| 国产尤物一区二区在线| zzijzzij亚洲日本少妇熟睡| 日本丶国产丶欧美色综合| 欧美肥妇毛茸茸| 中文字幕av一区 二区| 亚洲一区二区精品久久av| 久久不见久久见免费视频1| 国产91丝袜在线播放| 欧美日韩国产乱码电影| 精品国产一区二区三区四区四 | 成人在线一区二区三区| 色94色欧美sute亚洲线路一久| 欧美在线观看你懂的| 精品少妇一区二区三区在线播放| 国产精品免费视频网站| 午夜精品福利一区二区三区av| 高清国产午夜精品久久久久久| 欧美唯美清纯偷拍| 欧美国产精品一区| 人人爽香蕉精品| 99久久精品99国产精品| 精品久久一区二区| 亚洲国产视频a| 豆国产96在线|亚洲| 日韩一级黄色大片| 亚洲视频一区在线| 国产美女视频91| 欧美日韩三级一区二区| 国产亚洲成aⅴ人片在线观看| 亚洲午夜精品网| 成人激情小说乱人伦| 精品欧美一区二区在线观看| 亚洲男女毛片无遮挡| 国产成a人亚洲精| 日韩亚洲欧美在线观看| 一区二区三区精品视频在线| 成人午夜免费电影| 精品国产三级电影在线观看| 亚洲第一主播视频| 91视频一区二区| 中文字幕精品在线不卡| 老司机一区二区| 欧美一区二区视频在线观看| 亚洲国产一区二区在线播放| av资源站一区| 国产精品每日更新在线播放网址| 韩国一区二区视频| 日韩午夜中文字幕| 亚洲国产综合在线| 99国产欧美另类久久久精品| 久久久91精品国产一区二区精品| 麻豆精品在线播放| 日韩一区二区三区在线观看| 亚洲成在线观看| 一本久久精品一区二区| 国产精品久久久久久久蜜臀| 国产电影精品久久禁18| 久久男人中文字幕资源站| 久久99久久99小草精品免视看| 欧美一级欧美一级在线播放| 婷婷开心久久网| 欧美久久免费观看| 舔着乳尖日韩一区| 欧美一区三区二区| 秋霞午夜鲁丝一区二区老狼| 欧美精品久久99久久在免费线 | 日韩av在线发布| 91精品国产综合久久小美女| 亚洲第一电影网| 欧美日韩mp4| 日韩**一区毛片| 日韩一区二区三区在线| 国内外成人在线视频| 精品国产乱子伦一区| 久久成人免费电影| 中文字幕欧美日韩一区| av在线播放不卡| 一个色在线综合| 欧美日韩成人一区| 精品在线免费观看| 国产欧美一区二区三区鸳鸯浴| 福利视频网站一区二区三区| 亚洲日韩欧美一区二区在线| 欧美主播一区二区三区美女| 天堂成人免费av电影一区| 日韩精品一区二区三区中文不卡 | 91免费观看视频| 一区二区在线观看免费| 制服丝袜中文字幕亚洲| 韩国三级电影一区二区| 国产精品丝袜久久久久久app| 91小视频免费观看| 天堂成人国产精品一区| 欧美成人一区二区三区在线观看| 国产精一区二区三区| 亚洲欧洲一区二区在线播放| 欧美日韩免费在线视频| 麻豆视频一区二区| 中文在线资源观看网站视频免费不卡| 91麻豆6部合集magnet| 天堂精品中文字幕在线| 国产亲近乱来精品视频 | 日韩免费看的电影| 成人免费高清在线观看| 亚洲一区在线播放| 欧美精品一区二区高清在线观看| 岛国一区二区在线观看| 天天色 色综合| 日本一二三四高清不卡| 欧美人妖巨大在线| 成人中文字幕合集| 日韩不卡手机在线v区| 中文字幕精品一区二区精品绿巨人| 欧美在线播放高清精品| 国产一区二区三区最好精华液| 亚洲理论在线观看| 久久毛片高清国产| 欧美日韩精品电影| bt欧美亚洲午夜电影天堂| 久久国产精品免费| 一区二区三区免费网站| 久久久国产精品午夜一区ai换脸| 欧美日韩一级大片网址| 国产91清纯白嫩初高中在线观看| 亚洲va欧美va人人爽午夜| 国产精品欧美一级免费| 欧美成人官网二区| 欧美日韩性生活| 91视频91自| 懂色av中文字幕一区二区三区| 久久成人免费电影| 天天综合网 天天综合色|