嵌入式系統中有不少場所須要解析字符串,如解析GPS的RMC幀,解析用戶經過串口輸入的監控命令等。通常的作法是先接受一幀字符數據,而後用sscanf函數提取相應字段。程序員
int sscanf( const char *buffer, const char *format [, argument ] ... );
sscanf
屬於scanf
函數家族一員,從輸入源——字符串中讀取字符並根據format
給出的格式代碼對它們進行轉換,省略號表明可變長度的指針列表。函數
format
字符串參數中的格式代碼能夠由4部分組成:% [*] [width] [h|l|L]
格式碼fetch
如sscanf("...", "%4hd", &short_val)
中%4hd
表示從字符串中提取寬度限制爲4個數字的短整型。指針
如接受到用戶輸入的一個CLI命令,讀取0x0012
地址的值:code
rcv_buf = "$READ:0x0012" // 從rcv_buf裏面提取用戶須要讀取的值 fetch_num = sscanf(rcv_buf, "$READ:%x", &read_address);
若是執行成功,該函數返回值fetch_num
等於1
,read_address==0x12
,提取失敗的話fetch_num==0
*sscanf
函數能夠提取字符串%s
,單個字符%c
,整型%d
,%x
,能夠指定提取的整型的寬度,指定提取的浮點數的小數位數等等。orm
使用該函數尤爲要注意的是:第3部分的指針參數的類型如上述的read_address的類型必定要和第2部分format格式代碼中的參數的%x相匹配,在提取多個值時,一不當心,後面提取的值會把前面的所有覆蓋掉。舉個例子:字符串
typedef struct { char month; char day; short year; }DATE_T; DATE_T current_date = {0}; fetch_num = sscanf("$TIME:20120228","$TIME:%4u%2u%2u", ¤t_date.year, ¤t_date.month, ¤t_date.day)
按照程序員的思路,提取出來的結果應該是:year = 2012, month=2, day = 28
,
可是實際結果倒是year=0, month = 2, day=28
原型
緣由就在於:%u
提取的month
是32位無符號整型,函數會把目的地址看成一個32位整形的地址,所以就杯具了,DATE_T
結構體佔用4
字節,裏面¤t_date.month
實際是指向第1個字節的地址,若是被看成指向unsigned int
的地址,把月份month=0x0000 0002
的值拷貝過去,前面提取的佔用高2
字節的year
就會被覆蓋掉,而後原本提取的year
的值變成了0x0000
編譯器
sscanf
裏的地址所在的參數類型保持和第2部分的format
格式化部分一致編譯
typedef struct { unsigned int month; unsigned int day; unsigned int year; }DATE_T;
sscanf
函數避免了手工操做字符串之類重複發明輪子的行爲,尤爲注意該函數不會驗證指針參數的類型是否對應format
格式代碼中的正確類型。
- format格式不一樣編譯器處理不一樣:ARM能夠有空格
%u %d
,DSP C2000編譯器必須是%u%d
- 有些老51單片機的編譯器
format
裏不支持超過4個數值的fetch
!- 對於
=%x
的format,"=0x30"與"=30"效果同樣,自動剔除數字簽名的0x