博客 / 詳情

返回

嵌入式的json解析庫對比:cjson vs jsmn

在做物聯網應用中,需要和服務器做通信,經常使用json格式。
cjson是常用的解析庫,功能強大。
https://github.com/DaveGamble/cJSON
jsmn利用了零拷貝,減少了內存的使用,適合小資源嵌入式系統。
https://github.com/zserge/jsmn
下面直接從使用角度進行對比:

解析

cjson:開箱即用

cJSON* json = cJSON_Parse(json_str);

jsmn:需要提前定義好足夠的token數量

jsmntok_t tokens[256];
jsmn_parser parser;
jsmn_init(&parser);
int num = jsmn_parse(&parser, json_str, strlen(json_str), tokens, 256);

獲取對象

cjson:

cJSON* sn = cJSON_GetObjectItemCaseSensitive(json, "sn");

jsmn:

jsmntok_t* sn;
for(int i = 0; i < num; i++) {  //並不能排除子對象中重名的值
    jsmntok_t* t = &tokens[i];
    jsmn_get_item(json_str, t, "sn", &sn);
}

獲取數值

cjson:使用指針
jsmn:原字符串需要一直傳遞下來

字符串

cjson:

if(cJSON_IsString(sn) && (sn->valuestring != NULL))
{
    PRINTLN("sn:%s", sn->valuestring);
}

jsmn:無法得到0結尾的完整字符串

if(jsmn_is_string(json_str, sn))
{
    uint8_t* sn_ptr;
    uint8_t sn_len;
    jsmn_get_string(json_str, sn__, &sn_ptr, &sn_len);
    PRINTLN("sn:%.*s", sn_len, sn_ptr);
}

數字

cjson:

if(cJSON_IsNumber(spo2))
{
    PRINTLN("spo2:%d", spo2->valueint);
}

jsmn:

if(jsmn_is_number(json_str, spo2))
{
    PRINTLN("spo2:%d", jsmn_get_number(json_str, spo2));
}

浮點

cjson:

if(cJSON_IsNumber(volt))
{
    PRINTLN("volt:%f", volt->valuedouble);
}

jsmn:

if(jsmn_is_float(json_str, volt))
{
    PRINTLN("volt:%f", jsmn_get_float(json_str, volt));
}

數組

cjson:

cJSON* gyro;
if(cJSON_IsArray(gyros))
{
    PRINT("gyro(%d):", cJSON_GetArraySize(gyros));
    cJSON_ArrayForEach(gyro gyros)
    {
        if(cJSON_IsNumber(gyro))
        {
            PRINT("%d,", gyro->valueint);
        }
    }
    PRINT("\n");
}

jsmn:

if(jsmn_is_array(json_str, gyros))
{
    PRINT("gyro(%d):", jsmn_get_array_len(json_str, gyros));
    for(uint8_t i = 0; i < jsmn_get_array_len(json_str, gyros); i++) {
        jsmntok_t* gyro;
        jsmn_get_array_item(json_str, gyros, i, &gyro);
        if(jsmn_get_number(json_str, gyro))
        {
            PRINT("%d,", jsmn_get_number(json_str, gyro));
        }
    }
    PRINT("\n");
}

子對象獲取

cjson:

cJSON* irs = cJSON_GetObjectItemCaseSensitive(ppg, "ir");
cJSON* reds = cJSON_GetObjectItemCaseSensitive(ppg, "red");

jsmn:

jsmntok_t* irs;
jsmntok_t* reds;
for(int i = 0; i < jsmn_get_object_token_num(json_str, ppg); i++) {
    jsmntok_t* t = &ppg[i];
    jsmn_get_item(json_str, t, "ir" , &irs);
    jsmn_get_item(json_str, t, "red", &reds);
}

小結

jsmn雖然看起來高效和資源使用少,但是太原始。解析無嵌套無數組的json很方便,如果json嵌套比較複雜,解析代碼看起來就很麻煩。
cjson代碼寫得稍微深奧,封裝過多,不太適合小資源的嵌入式用。內存使用稍大,因為把原數據全都做了值拷貝。但優點是各對象使用了鏈表,對於嵌套的json處理方便。

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.