嵌入式軟體除錯常用知識點
本部落格參考王利濤老師的教程,以及自己之前學習的知識點,特此總結。主要涉及輸入輸出重定向和巨集定義的一些用法。
一、 輸入輸出重定向
在Linux中,所有對裝置和檔案的操作都使用檔案描述符來進行。Linux中一個程式啟動時,都會開啟3個檔案:標準輸入、標準輸出和標準出錯處理。這三個檔案分別對應檔案描述符0、1、2。即:
標準輸入流:stdin
標準輸出流:stdout
標準錯誤輸出流:stderr
程式開始執行時,系統自動開啟3個標準檔案:標準輸入、 標準輸出、標準出錯輸出。通常這3個檔案都與終端相聯絡。因此,以前我們所用到的從終端輸入或輸出都不需要開啟終端檔案。系統自定義了3個檔案指標stdin、stdout、stderr,分別指向終端輸入、終端輸出和標準出錯輸出(也從終端輸出)。
在C語言中,提供了5種標準流,所有流均以檔案的形式出現,統一了各種硬體操作介面帶來的差異。
因此,我們從兩方面使用它,分別是SHELL終端和程式方面:
1.1 SHELL終端的重定向
1)重定向輸出:
> 覆蓋方式
>> 追加方式
>! 強制覆蓋方式
舉例: cat main.c > log 將main.c中的內容輸出到Log檔案中
2)重定向輸入:
<
舉例: grep main < log 將log檔案內容輸入到終端,同時grep檢視關鍵字main所在位置
3) 重定向標準錯誤
2> 標準錯誤以覆蓋的方式寫入檔案
2>> 追加
舉例: 命令 物件 1>log 2>err linux命令操作物件時,正常輸出到log檔案,錯誤輸出到err檔案(1可以省略)
1.2 C語言使用freopen函式重定向
如題,這裡使用劉汝佳的演算法競賽書中的例子作為說明。
#include <stdio.h>
#include <string.h>
#define LOCAL
int main()
{
#ifdef LOCAL
freopen("datain.txt","r",stdin);
freopen("dataout.txt","w",stdout);
#endif
int num;
scanf("%d",&num);
printf("%d",num);
return 0;
}
重定向部分被寫在#ifdef 和#endif ,其含義是:只有定義了符號LOCAL,才編譯兩條freopen函式。
這種方法適合在競賽中使用,我們不必每次從輸入終端讀取特定格式資料,可以將資料寫入在datain.txt檔案中,使能巨集定義,當最後除錯完畢後,失能巨集定義即可,非常方便!
二、 使用標準預定義巨集列印屬性
標準C語言預處理要求定義某些物件巨集,每個預定義巨集的名稱一兩個下劃線字元開頭和結尾,這些預定義巨集不能被取消定義(#undef)或由程式設計人員重新定義。這裡僅僅列舉常用的幾個:
__LINE__ 當前程式行的行號,表示為十進位制整型常量
__FILE__ 當前原始檔名,表示字串型常量
__DATE__ 轉換的日曆日期,表示為Mmm dd yyyy 形式的字串常量,Mmm是由asctime產生的。
__TIME__ 轉換的時間,表示"hh:mm:ss"形式的字串型常量,是有asctime產生的。(asctime貌似是指的一個函式)
舉例:
#include <stdio.h>
#include <string.h>
void why_me()
{
printf( "This function is %s\n", __func__ );
printf( "The file is %s.\n", __FILE__ );
printf( "This is line %d.\n", __LINE__ );
}
int main()
{
printf( "The file is %s.\n", __FILE__ );
printf( "The date is %s.\n", __DATE__ );
printf( "The time is %s.\n", __TIME__ );
printf( "This is line %d.\n", __LINE__ );
printf( "This function is %s.\n", __func__ );
why_me();
return 0;
}
大家可以看到這種寫法的好處了吧,特別是當被呼叫函式出錯時,我們可以利用這些列印資訊很快的定位到出錯的位置,方便快速除錯。
三、 列印緩衝問題
有時候我們發現我們使用printf()函式列印時,並不能立即列印出我們想要的資訊。而是在某個事件觸發後(比如換行、緩衝區滿等),才列印出我們的資訊,這是為什麼呢?
原因是printf()函式採用行緩衝機制,減少了I/O時間與磁碟讀寫時間,提高了系統效能。但是,也帶來了問題,就是不能實時列印資訊,這裡提供幾種解決方案解決行緩衝帶來的延遲
- 在printf裡新增\n
- 重新整理緩衝區:fflush(stdout);
- 直接將緩衝區禁掉: setvbuf(stdout,NULL,_IONBF,0);
- 使用錯誤標準流,stdout有line buffer: fprintf(stderr,…)
四、 列印開關控制
列印日誌雖然能方便快速除錯,但是有時也帶來了問題,筆者最近也遇到了這種問題。在嵌入式對時序要求較高的場景下,列印非常影響系統的效能。 因此,我們可以使用列印開關,在DEBUG版本時,我們可以列印資訊,而在Realease版本時,我們不輸出除錯資訊。
這裡利用了一個知識點,C99標準對可變引數巨集的支援:__VA_ARGS__
程式碼:
#include <stdio.h>
#include <string.h>
#define __DEBUG
#ifdef __DEBUG
#define DEBUG(...) printf(__VA_ARGS__)
#else
#define DEBUG(...)
#endif
int main()
{
DEBUG("hello %s\n","paopao");
DEBUG("value %s %d\n","wsq",1000);
return 0;
}
五、 列印等級控制
有時,我們需要根據當前列印級別進行有選擇的除錯資訊輸出,此時就需要對列印進行等級控制。
程式碼:
#include <stdio.h>
#include <string.h>
#define ERR_LEVEL 1
#define WARN_LEVEL 2
#define DEBUG_LEVEL 3
/*
PRINT_LEVEL setting :
0: printf off
1: err log
2: warning conditions
3: debug_level messages
*/
#define PRINT_LEVEL 2
#define ERR(...) \
do{ \
if(PRINT_LEVEL>=ERR_LEVEL) \
{ \
printf(__VA_ARGS__); \
} \
}while(0)
#define WARN(...) \
do{ \
if(PRINT_LEVEL>=WARN_LEVEL) \
{ \
printf(__VA_ARGS__); \
} \
}while(0)
#define DEBUG(...) \
do{ \
if(PRINT_LEVEL>=DEBUG_LEVEL) \
{ \
printf(__VA_ARGS__); \
} \
}while(0)
int main()
{
ERR("erron log....\n");
WARN("warning log...\n");
DEBUG("debug log ...\n");
return 0;
}
這裡我們根據PRINT_LEVEL 巨集定義進行有選擇的列印資訊輸出,能夠很好的控制程式除錯資訊輸出。
注:這裡巨集定義使用了接續符的概念,注意接續符’\’後面不要出現空格,否則會出現警告:
backslash and newline separated by space
相關文章
- 學習除錯實時嵌入式軟體除錯
- webpack常用知識點Web
- SVN - 常用知識點
- 軟體除錯斷點之小記除錯斷點
- Flow 常用知識點整理
- vue常用的知識點Vue
- Angular常用知識點梳理Angular
- GCC除錯基礎知識GC除錯
- 學嵌入式Linux軟體開發需要的知識薦Linux
- Koa 框架常用知識點整理框架
- RabbitMQ 常用知識點總結MQ
- Python常用知識點一二Python
- 軟體除錯 (轉)除錯
- 嵌入式作業系統—重點知識作業系統
- 五個UICollectionView常用的知識點UIView
- ES6常用知識點概述
- PHP 易錯知識點整理PHP
- JavaScript 易錯知識點整理JavaScript
- JavaScript易錯知識點整理JavaScript
- 【Java】Debug斷點除錯常用技巧Java斷點除錯
- PLSQL一些常用的知識點SQL
- MySQL 常用易混淆知識點總結MySql
- 常用的機器學習&資料探勘知識(點)機器學習
- 錯題知識點回顧1
- 做資料分析必需掌握的軟體和知識點
- 做資料分析要掌握哪些軟體和知識點?
- 信管知識梳理(三)軟體工程相關知識軟體工程
- 嵌入式基礎(2)---硬體基礎知識
- 嵌入式軟體開發的特點、設計流程、嵌入式軟體的結構
- ES6常用知識點總結(上)
- ES6常用知識點總結(下)
- 【JavaScript】不常用知識點復(yù)習(一)JavaScript
- Java Web知識點--常用演算法(4)JavaWeb演算法
- rman配置及常用操作相關知識點
- asp.net 常用知識點彙總整理ASP.NET
- 彙編必知小知識點及常用debug命令
- 訊息中介軟體之RabbitMQ關鍵知識點總結MQ
- 知識點!!8類常見惡意軟體以及如何識別它們