cJSON的使用
1 安裝cJSON
github地址://github.com/DaveGamble/cJSON.git
-
下載完成後進入cJSON目錄,執行下面命令生成Makefile文件
mkdir build cd build cmake ..
-
執行下面命令安裝cJSON庫
make install
- 默認將頭文件安裝到
/usr/local/include/cjson
路徑下 - 默認將鏈接庫安裝到
/usr/local/lib
路徑下
- 默認將頭文件安裝到
-
一些CMake選項介紹
選項 功能 默認值 -DENABLE_CJSON_TEST
開啟編譯tests On -DENABLE_CJSON_UTILS
開啟編譯cJSON_Utils Off -DENABLE_TARGET_EXPORT
開啟CMake目標導出 On -DENABLE_CUSTOM_COMPILER_FLAGS
開啟自定義編譯選項 On -DENABLE_VALGRIND
使用valgrind運行tests Off -DENABLE_SANITIZERS
使用AddressSanitizer和UndefinedBehaviorSanitizer編譯cJSON Off -DENABLE_SAFE_STACK
開啟SafeStack工具檢測(目前只能在Clang編譯器上工作) Off -DBUILD_SHARED_LIBS
編譯動態庫 On -DBUILD_SHARED_AND_STATIC_LIBS
編譯動態庫和靜態庫 Off -DCMAKE_INSTALL_PREFIX
設置安裝路徑前綴 -DENABLE_LOCALES
開啟使用localeconv方法 On -DCJSON_OVERRIDE_BUILD_SHARED_LIBS
使用 -DCJSON_BUILD_SHARED_LIBS
覆蓋BUILD_SHARED_LIBS
的值 -
在程式碼中引入頭文件
#include <cjson/cJSON.h>
2 cJSON數據結構
-
cJSON使用
cJSON
結構體表示JSON數據typedef struct cJSON { /* next和prev允許你遍歷array/object鏈,或者使用GetArraySize/GetArrayItem/GetObjectItem方法 */ struct cJSON *next; struct cJSON *prev; /* array/object會擁有child指針,指向它包含的一連串元素 */ struct cJSON *child; /* 類型 */ int type; /* 如果type為cJSON_String或cJSON_Raw,使用它保存string值 */ char *valuestring; /* 將值寫入valueint已過時,使用cJSON_SetNumberValue代替 */ int valueint; /* 如果type為cJSON_Number,使用它保存number值 */ double valuedouble; /* 如果該節點是array或者object的子元素,則使用它保存名稱字元串 */ char *string; } cJSON;
-
type
取值取值 含義 備註 檢查 cJSON_Invalid
非法 不包含任何值 cJSON_IsInvalid
cJSON_False
false
cJSON_IsFalse
/cJSON_IsBool
cJSON_True
true
cJSON_IsTrue
/cJSON_IsBool
cJSON_NULL
null
cJSON_IsNull
cJSON_Number
數字 值將以 double
類型保存在valuedouble
中,同時也保存在valueint
中,如果超出整形範圍,則valueint
值為INT_MAX
或者INT_MIN
cJSON_IsNumber
cJSON_String
字元串 以 '\0'
結尾的形式保存在valuestring
中cJSON_IsString
cJSON_Array
數組 child
指針指向數組中各個元素,各元素通過next
/prev
指針串在一起形成鏈表cJSON_IsArray
cJSON_Object
對象 同數組保存形式相同,只不過對象中的各個元素會將它們的key值存儲在 string
中cJSON_IsObject
cJSON_Raw
任意JSON類型 以 '\0'
結尾的形式保存在valuestring
中,使用cJSON解析時不會生成這個類型,並且cJSON不會校驗JSON的合法性cJSON_IsRaw
cJSON_IsReference
引用 child
指向的元素或者valuestring
不被當前節點擁有,當使用cJSON_Delete
時,只會釋放當前節點,而不會釋放它的child
和valuestring
cJSON_StringIsConst
常量字元串 string
指向一個常量字元串,當使用cJSON_Delete
時,將不會釋放string
3 創建cJSON數據
對於每種type,都有一個與之對應的cJSON_Create...
方法用於創建該類型的節點,所有方法都會創建一個cJSON
結構體,可以使用cJSON_Delete
釋放它
注意:
- 不能使用
cJSON_Delete
釋放array或object當中的元素,當array或者object被釋放時,其中的元素也會自動釋放 - 可以使用
cJSON_SetValueString
改變cJSON_String
節點的valuestring
值,而不需要手動釋放之前的valuestring
3.1 基本類型
類型 | 創建方法 | 說明 |
---|---|---|
null | cJSON_CreateNull |
|
boolean | cJSON_CreateTrue /cJSON_CreateFalse /cJSON_CreateBool |
|
number | cJSON_CreateNumber |
將同時設置valuedouble 和valueint ,如果數字的值超過整形範圍,則valueint 將被設為INT_MAX 或INT_MIN |
string | cJSON_CreateString /cJSON_CreateStringReference |
cJSON_CreateString 會拷貝字元串,而cJSON_CreateStringReference 直接指向設置的字元串 |
3.2 數組
3.2.1 創建數組
cJSON_CreateArray
:創建一個空數組cJSON_CreateArrayReference
:創建一個數組,但是它裡面的所有元素都不屬於它自己,所以不能使用cJSON_Delete
刪除它裡面的內容
3.2.2 向數組中添加元素
cJSON_AddItemToArray
:在數組尾端添加元素cJSON_AddItemReferenceToArray
:將另一個元素的引用添加進數組cJSON_InsertItemInArray
:在指定索引處插入元素
3.2.3 獲取數組中的元素
-
cJSON_GetArrayItem
:根據索引獲取元素 -
cJSON_DetachItemFromArray
:根據索引獲取數組中的元素,並將其從數組中分離,以便後續能夠繼續使用
3.2.4 刪除數組中的元素
cJSON_DeleteItemFromArray
:根據索引刪除數組中的元素
3.2.5 替換數組中的元素
cJSON_ReplaceItemInArray
:根據索引替換元素cJSON_ReplaceItemViaPointer
:根據指針替換元素,失敗返回0
3.2.6 獲取數組的大小
cJSON_GetArraySize
:獲取數組的大小
3.2.7 迭代數組中的元素
cJSON_ArrayForEach
:在\(O(n)\)的時間內迭代數組中的元素
3.3 對象
3.3.1 創建對象
cJSON_CreateObject
:創建一個空對象cJSON_CreateObjectReference
:創建一個對象,但是它裡面的所有元素都不屬於它自己,所以不能使用cJSON_Delete
刪除它裡面的內容
3.3.2 向對象中添加元素
cJSON_AddItemToObject
:向對象中添加一個元素cJSON_AddItemToObjectCS
:向對象中添加一個名稱(對象的key,即cJSON
結構體中的string
)為常量或者引用的元素cJSON_AddItemReferenceToObject
:將另一個元素的引用添加進對象
3.3.3 獲取對象中的元素
-
cJSON_GetObjectItemCaseSensitive
:獲取對象中的元素 -
cJSON_DetachItemFromObjectCaseSensitive
:分離並獲取對象中的元素
3.3.4 刪除對象中的元素
cJSON_DeleteItemFromObjectCaseSensitive
:刪除對象中的元素
3.3.5 替換對象中的元素
cJSON_ReplaceItemInObjectCaseSensitive
:根據key替換對象中的元素cJSON_ReplaceItemViaPointer
:根據指針替換對象中的元素,失敗返回0
3.3.6 獲取對象的大小
cJSON_GetArraySize
:獲取對象的大小
3.3.7 迭代對象中的元素
cJSON_ArrayForEach
:迭代對象中的元素
3.3.8 快速創建並添加元素到對象
cJSON提供了快速創建並添加到對象的方法,這些方法返回指向新創建元素的指針,如果失敗,則返回NULL
cJSON_AddNullToObject
cJSON_AddTrueToObject
cJSON_AddFalseToObject
cJSON_AddBoolToObject
cJSON_AddNumberToObject
cJSON_AddStringToObject
cJSON_AddRawToObject
cJSON_AddObjectToObject
cJSON_AddArrayToObject
4 cJSON解析與輸出JSON
4.1 解析JSON
cJSON提供的解析函數的返回值需要手動調用cJSON_Delete
釋放
-
cJSON_Parse
:解析以'\0'
結尾的JSON字元串cJSON * cJSON_Parse(const char *value);
-
cJSON_ParseWithLength
:解析指定長度的JSON字元串(可以不以'\0'
結尾)cJSON * cJSON_ParseWithLength(const char *value, size_t buffer_length);
-
cJSON_ParseWithOpts
cJSON * cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
return_parse_end
:返回指向輸入字元串中JSON的結束位置,或解析出錯的位置require_null_terminated
:是否禁止輸入字元串中的JSON後面還包含有數據
-
cJSON_ParseWithLengthOpts
cJSON * cJSON_ParseWithLengthOpts(const char *value, size_t buffer_length, const char **return_parse_end, cJSON_bool require_null_terminated);
4.2 輸出JSON
cJSON提供的輸出函數的返回值需要手動調用free
釋放
-
cJSON_Print
:輸出經過空白字元格式化後的JSONchar * cJSON_Print(const cJSON *item);
-
cJSON_PrintUnformatted
:輸出沒有經過空白字元格式化後的JSONchar * cJSON_PrintUnformatted(const cJSON *item);
-
cJSON_PrintBuffered
:輸出JSON到指定大小的bufferchar * cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt);
prebuffer
:指定輸出buffer的初始大小fmt
:是否使用空白字元進行格式化
-
cJSON_PrintPreallocated
:輸出JSON到靜態buffer,從而避免動態分配記憶體,當buffer大小不夠時,調用失敗,返回0,成功時返回1cJSON_bool cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format);
注意:至少提供5位元組大小的buffer
5 cJSON使用示例
{
"name": "Awesome 4K",
"resolutions": [
{
"width": 1280,
"height": 720
},
{
"width": 1920,
"height": 1080
},
{
"width": 3840,
"height": 2160
}
]
}
5.1 列印輸出JSON
5.1.1 方法1
//create a monitor with a list of supported resolutions
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor(void)
{
const unsigned int resolution_numbers[3][2] = {
{1280, 720},
{1920, 1080},
{3840, 2160}
};
char *string = NULL;
cJSON *name = NULL;
cJSON *resolutions = NULL;
cJSON *resolution = NULL;
cJSON *width = NULL;
cJSON *height = NULL;
size_t index = 0;
cJSON *monitor = cJSON_CreateObject();
if (monitor == NULL)
{
goto end;
}
name = cJSON_CreateString("Awesome 4K");
if (name == NULL)
{
goto end;
}
/* after creation was successful, immediately add it to the monitor,
* thereby transferring ownership of the pointer to it */
cJSON_AddItemToObject(monitor, "name", name);
resolutions = cJSON_CreateArray();
if (resolutions == NULL)
{
goto end;
}
cJSON_AddItemToObject(monitor, "resolutions", resolutions);
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
{
resolution = cJSON_CreateObject();
if (resolution == NULL)
{
goto end;
}
cJSON_AddItemToArray(resolutions, resolution);
width = cJSON_CreateNumber(resolution_numbers[index][0]);
if (width == NULL)
{
goto end;
}
cJSON_AddItemToObject(resolution, "width", width);
height = cJSON_CreateNumber(resolution_numbers[index][1]);
if (height == NULL)
{
goto end;
}
cJSON_AddItemToObject(resolution, "height", height);
}
string = cJSON_Print(monitor);
if (string == NULL)
{
fprintf(stderr, "Failed to print monitor.\n");
}
end:
cJSON_Delete(monitor);
return string;
5.1.2 方法2
使用cJSON_Add...ToObject
快捷創建和添加元素
//NOTE: Returns a heap allocated string, you are required to free it after use.
char *create_monitor_with_helpers(void)
{
const unsigned int resolution_numbers[3][2] = {
{1280, 720},
{1920, 1080},
{3840, 2160}
};
char *string = NULL;
cJSON *resolutions = NULL;
size_t index = 0;
cJSON *monitor = cJSON_CreateObject();
if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
{
goto end;
}
resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
if (resolutions == NULL)
{
goto end;
}
for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
{
cJSON *resolution = cJSON_CreateObject();
if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
{
goto end;
}
if (cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
{
goto end;
}
cJSON_AddItemToArray(resolutions, resolution);
}
string = cJSON_Print(monitor);
if (string == NULL)
{
fprintf(stderr, "Failed to print monitor.\n");
}
end:
cJSON_Delete(monitor);
return string;
}
5.2 解析JSON
/* return 1 if the monitor supports full hd, 0 otherwise */
int supports_full_hd(const char * const monitor)
{
const cJSON *resolution = NULL;
const cJSON *resolutions = NULL;
const cJSON *name = NULL;
int status = 0;
cJSON *monitor_json = cJSON_Parse(monitor);
if (monitor_json == NULL)
{
const char *error_ptr = cJSON_GetErrorPtr();
if (error_ptr != NULL)
{
fprintf(stderr, "Error before: %s\n", error_ptr);
}
status = 0;
goto end;
}
name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
if (cJSON_IsString(name) && (name->valuestring != NULL))
{
printf("Checking monitor \"%s\"\n", name->valuestring);
}
resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
cJSON_ArrayForEach(resolution, resolutions)
{
cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
{
status = 0;
goto end;
}
if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
{
status = 1;
goto end;
}
}
end:
cJSON_Delete(monitor_json);
return status;
}