<var id="fnfpo"><source id="fnfpo"></source></var>
<rp id="fnfpo"></rp>

<em id="fnfpo"><object id="fnfpo"><input id="fnfpo"></input></object></em>
<em id="fnfpo"><acronym id="fnfpo"></acronym></em>
  • <th id="fnfpo"><track id="fnfpo"></track></th>
  • <progress id="fnfpo"><track id="fnfpo"></track></progress>
  • <tbody id="fnfpo"><pre id="fnfpo"></pre></tbody>

  • x
    x

    嵌入式系統上的簡易printf

    發布時間:2009-11-27 19:09    發布者:linux_Ultra
    關鍵詞: printf , 嵌入式系統
    嵌入式系統上的簡易printf
    windstorm on 2008-12-30,17:02 1,097 views Comments (3)
    此文針對嵌入式軟件的業余初學者,高手請自行路過打醬油。
    嵌入式中,調試手段通常有兩種,一是遠程gdb,一是直接printf。如果是調試自己玩的小板子,用gdb有點大張旗鼓了,大多數情況下printf就可以搞定。不過printf的問題是stdiolib的size太大,稍微有點程序,加上幾個常用的庫,比如stdio和string,超過16k甚至32k(已經大于一些低端芯片的flash容量了)是很正常的事情,而且通常比較慢,程序越多,越麻煩。道理很簡單,標準C語言庫的規范中,Printf()必須處理大量的數據格式,包括字符串、字符、(各種長度的有符號和無符號)數字,以及浮點值。而且格式字符串還要包括用于更改文本對齊、基數、間距、字段寬度和精度的調節器和指示器。符合這個規范的代碼必然會是冗長和繁重的。一些嵌入式系統庫倒是提供了一些之針對整數的printf,但還是有問題,首先是還是太大,其次是你沒有自己的調整權限。
    其實printf也就是IO的調用包裝而已,我們完全可以自己寫一個簡易版本的printf滿足自己的需要,并隨時根據需要裁剪。具體來說,printf在這里要起的作用就是將調試字符串從嵌入式目標空閑的串口壓出,并在運行于宿主工作站的終端模擬器上顯示結果。下面就簡單介紹一下,如何來自己寫一個簡易printf函數。


    要寫printf,首先要知道什么是可變參數傳遞,我們來看看標準庫里面,是如何定義可變參數實現的:

    #define _AUPBND (sizeof (acpi_native_int) - 1)
    #define _ADNBND (sizeof (acpi_native_int) - 1)
    #define _bnd(X, bnd) (((sizeof (X)) + (bnd)) & (~(bnd)))
    #define va_arg(ap, T) (*(T *)(((ap) += (_bnd (T,_AUPBND))) - (_bnd (T,_ADNBND))))
    #define va_end(ap) (void) 0
    #define va_start(ap, A) (void) ((ap) = (((char *) &(A)) +(_bnd(A,_AUPBND))))
    關于可變參數的原理,網上有一些文章,總結來說,就是我們可以通過Intel80×86機器的對齊特性來獲得所有的參數,因為在Intel80×86機器上,每個變量的地址都要是sizeof(int)的倍數,這樣能提升CPU運行的效率。也就是說,所有參數的首地址都要是4的倍數,就算你是char型的,那浪費3個byte也要安排你占第四個坑。
    好,由于C語言傳遞參數時是用push指令從右到左將參數逐個壓棧,因此我們通過棧指針跳4n格來訪問第n個參數,不要忘了,參數的地址都是字對齊的。這里,我們用#define _bnd(X, bnd) (((sizeof (X)) + (bnd)) &(~(bnd)))來計算類型為X的參數在棧中占據的字對齊后的字節數。bnd是sizeof (acpi_native_int) –1,acpi_native_unit在32位機的定義是:
    typedef u32 acpi_native_uint;
    所以( ~(bnd))就是0xfffffffc 。 因此,_bnd(X,bnd) 宏在32位機下就是
      ( (sizeof(X) + 3)&0xfffffffc )
    很明顯,其作用是–倘若sizeof(X)不是4的整數倍,將其變為4的整數倍。
    va_start(ap,A) 負責初始化參數指針ap,將函數參數A右邊第一個參數的地址賦給ap,這個第一個參數通常就是printf里面的”%x%d%f%d”。
    va_arg(ap,T) 可以獲得ap指向參數的值,并使ap指向下一個參數,T用來指明當前參數類型。
    在這里,上述代碼還是麻煩,而且sizeof我們也不能直接用,所以我們不如干脆直接寫一個不那么麻煩而有針對性的可變參數操作定義:
    #define sizeof(x) ((char *)(&x+1) - (char *)(&x))
    #define va_start(ap,v)  ( ap = (char *)&v + sizeof(v) )
    #define va_arg(ap,t)    ( *(t *)((ap += sizeof(t)) - sizeof(t)) )
    #define va_end(ap)      ( ap = (char *)0 )
    有了這幾個定義,print函數就好寫了,為了節省空間,這個簡單的print()只支持“%s”,“%d”和”%c”格式的分類符,暫時不需要其他功能,比如格式對齊之類的,當然,可以根據自己的需要擴展這個函數。
    int print( const char *fmt, ... )
    {
      const char *s;
      char c;
      int d;
      va_list ap;
      va_start(ap, fmt);
      while( *fmt != '\0' )
      {
        if( *fmt != '%' )
        {
          uart_putc(*fmt++);
          continue;
        }
        switch(*++fmt)
        {
          case 's':
          {
            s = va_arg(ap, const char *);
            uart_puts(s);
            break;
          }
          case 'd':
          {
            d = va_arg(ap, int);
            uart_putints(d, 10);
            break;
          }
          case 'c':
          {
            c = va_arg(ap, char);
            uart_putc(c);
            break;
          }
          default:
            uart_putc(*fmt);
        }
        fmt++;
      }
      va_end(ap);
      return 1;
    }
    這里面有一些函數,uart_putc是串口驅動程序,給串口送東西的,uart_puts是簡單的多重putc包裝。uart_putints則需要做一些atoi的轉換,一個比較簡單但是有效的atoi程序宏定義如下:
    #define ATOI(X, result) \
    do{ \
    char *lptr = X; \
    result = 0; \
    while (1) \
    { \
    if ((*lptr >= '0') && (*lptr <= '9')) \
    { \
    result *= 10; \
    result += *lptr - '0'; \
    lptr++; \
    } \
    else \
    { \
    break; \
    } \
    } \
    }while(0)
    本文地址:http://www.portaltwn.com/thread-5878-1-1.html     【打印本頁】

    本站部分文章為轉載或網友發布,目的在于傳遞和分享信息,并不代表本網贊同其觀點和對其真實性負責;文章版權歸原作者及原出處所有,如涉及作品內容、版權和其它問題,我們將根據著作權人的要求,第一時間更正或刪除。
    您需要登錄后才可以發表評論 登錄 | 立即注冊

    廠商推薦

    • Microchip視頻專區
    • EtherCAT®和Microchip LAN925x從站控制器介紹培訓教程
    • MPLAB®模擬設計器——在線電源解決方案,加速設計
    • 讓您的模擬設計靈感,化為觸手可及的現實
    • 深度體驗Microchip自動輔助駕駛應用方案——2025巡展開啟報名!
    • 貿澤電子(Mouser)專區

    相關視頻

    關于我們  -  服務條款  -  使用指南  -  站點地圖  -  友情鏈接  -  聯系我們
    電子工程網 © 版權所有   京ICP備16069177號 | 京公網安備11010502021702
    快速回復 返回頂部 返回列表
    精品一区二区三区自拍图片区_国产成人亚洲精品_亚洲Va欧美va国产综合888_久久亚洲国产精品五月天婷