問題:
1. printf自帶的庫編譯出來的大小比較大(flash吃緊)
2. printf是一個不定長參數, 意味著函數無法知道傳入的長度. 解決這個問題有2中方法:1.設置足夠大小的數組作為參數存儲; 2. 使用動態內存分配的方式來做(應該使用的是這個方式).(內存吃緊)
問題解釋:
1. 之前寫裸機的時候從來沒思考過printf問題, 因為寫裸機的時候一般printf只是打印調試的時候日志, 打印完成后會關閉打印功能.因此在裸機中, 并且會關閉打印的時候這個還是可以使用的.
2. 大家應該也發現了,沒人在51單片計算串口重定向,然后調用系統的printf吧, 就是庫函數消耗內存和flash
?在實時系統中, 系統自帶的printf那就問題更多了:
? ? ? ? 1. 函數重入的問題, 也許有人會說我使用實時系統的互斥, 臨界區保護等,當然沒問題.
? ? ? ? 2. 其次我們知道實時系統中, 所有函數的開銷是設定堆棧大小的, 如果是系統庫用一個足夠大的數組作為數據存儲, 意味著堆棧會爆掉, 程序跑飛(系統中應該不會用這么傻的方法). 那如果是使用動態內存分配的方法, 那么這也將是一個不定時炸彈.為啥說是不定時炸彈呢? 因為printf必定調用的是系統malloc, 意味著可能會出現內存碎片.到時候可能申請不到內存, 打印功能就可能失效了.
? ?
問題解決:
? ? ? ? 由于我們公司的產品是工業產品, 用到了很多打印, 如果調用系統printf, 程序崩潰真的很難查.因此解決方法就是自己實現printf(我們的printf源碼是從linux內核抄過來的).? ??
? ? ? ? 而實際上, printf是通過snprintf封裝來的, 我們定義了一個靜態數組來存儲printf要打印的內容,,用snprintf打印里面的內容,? 這樣多線程中的每個線程的堆棧就只提供給任務使用.避免堆棧溢出照成的程序崩潰.(當然也可以用系統提供的snprintf替代自己實現的snprintf, 可能編譯代碼多點, 但不會出現不可靠的問題)
? ? ? ? 公司的項目代碼的打印只對輸出到串口進行了保護, 將數據復制到靜態數組并沒保護, 但是打印出來并沒有出現數據亂碼.
? ? ? ? 代碼使用的ucos2, 可以在中斷打印, 但是打印內部是關中斷了, 至少我知道freertos中任務關中斷和中斷關中斷是不一樣的, 沒學過ucos2, 可能是它自己特性, 本身可以做到.
? ? ? ? 細細推敲下來, 發現一個小小的printf都有各種問題, 何況自己寫的bug呢, 雖然公司的代碼讓我看的不爽, 但確實穩定,.