C語言——sscanf函數使用技巧

前言

嵌入式系統中有不少場所須要解析字符串,如解析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等於1read_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",
                &current_date.year, 
                &current_date.month, &current_date.day)

按照程序員的思路,提取出來的結果應該是:
year = 2012, month=2, day = 28
可是實際結果倒是
year=0, month = 2, day=28原型

緣由就在於:%u提取的month是32位無符號整型,函數會把目的地址看成一個32位整形的地址,所以就杯具了,DATE_T結構體佔用4字節,裏面&current_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格式代碼中的正確類型。

補充

  1. format格式不一樣編譯器處理不一樣:ARM能夠有空格%u %d,DSP C2000編譯器必須是%u%d
  2. 有些老51單片機的編譯器format裏不支持超過4個數值的fetch
  3. 對於=%x的format,"=0x30"與"=30"效果同樣,自動剔除數字簽名的0x
相關文章
相關標籤/搜索