cJSON解析器应用例子
cJSON是著名的开源C语言编写的JSON解析/打包器,占用资源少、效率高、方便移植,cJSON使用起来也十分方便,网络上也不乏cJSON的使用文章。
1.下载源码
cJSON源码仓库“ https://github.com/DaveGamble/cJSON ”,可以clone或者下载到本地。cJSON只需要一个源码文件和一个头文件,test.c是作者提供的测试例程。

2.测试例子
首先我们直接使用作者提供的测试程序“test.c”,作者也提供了Makefile,以在Linux环境下编译执行。但是,貌似本人的环境编译不过,所以自己重新写了个Makefile。
VERSION =
CC = gcc
DEBUG =
CFLAGS = -Wall -c
SOURCES = $(wildcard *.c)
INCLUDES =
LIB_NAMES =
LIB_PATH =
OBJ = $(patsubst %.c, %.o, $(SOURCES))
TARGET = cj-test
#links
$(TARGET):$(OBJ)
@mkdir -p output
$(CC) $(OBJ) $(LIB_PATH) $(LIB_NAMES) -o output/$(TARGET)$(VERSION)
@rm -rf $(OBJ)
#compile
%.o: %.c
$(CC) $(INCLUDES) $(DEBUG) $(CFLAGS) $^ -o $@
.PHONY:clean
clean:
@echo "Remove linked and compiled files......"
rm -rf $(OBJ) $(TARGET) output
“test.c”文件,作者提供了完整的JSON对象封装过程,包括字符串、数字、对象、数组等,并在将JSON对象打印在终端。执行make编译,在“output”目录生成执行文件“cj-test”。运行结果部分截图:

上面测试文件只是演示“封装”过程,解析过程并未包含,作者在GitHub仓库上的说明文档有举出源码例子。直接使用该例子测试。例子中,根据作者的英文描述,大体意思是解析一个关于“显示器参数”的JSON串,判断该显示器是否支持“4K”高清输出。
/* monitor JOSN对象 */
const char monitor[] = { \
"{ \
\"name\": \"Awesome 4K\", \
\"resolutions\": \
[ \
{ \
\"width\": 1280, \
\"height\": 720 \
}, \
{ \
\"width\": 1920, \
\"height\": 1080 \
} \
] \
}" \
};
/* 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:
resolution = cJSON_GetObjectItemCaseSensitive(monitor_json, "Play time");
if(cJSON_IsNumber(resolution))
{
printf("Play Time: \"%d\"\n", resolution->valueint);
}
if(status == 1)
{
printf("This monitor support full hd.\n");
}
else
{
printf("This monitor not suppord full hd.\n");
}
cJSON_Delete(monitor_json);
return status;
}
int CJSON_CDECL main(void)
{
/* print the version */
printf("Version: %s\n", cJSON_Version());
/* Now some samplecode for building objects concisely: */
//create_objects();
//supports_full_hd(create_monitor());
supports_full_hd(monitor);
如果不手动创建JSON对象,也可以直接使用作者描述文档中创建“monitor”对象的源码进行创建,然后再调用解析函数解析。
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 transfering 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);
cJSON_AddFalseToObject (resolution, "interlace");
cJSON_AddNumberToObject(resolution, "frame rate", 24);
}
if (resolutions == NULL)
{
goto end;
}
string = cJSON_Print(monitor);
if (string == NULL)
{
// fprintf(stderr, "Failed to print monitor.\n");
}
end:
cJSON_Delete(monitor);
printf("Monitor:%s\r\n",string);
return string;
}
添加到“test.c”文件中,重新编译执行:

3.使用关键注意点
【1】cJSON内部使用到动态内存,默认采用系统的“malloc”和“free”;可以在初始化阶段指定自己的内存管理函数,如“new”和“delete”。
cJSON_Hooks cJSON_hook;
cJSON_hook.malloc_fn = new;
cJSON_hook.free_fn = delete;
cJSON_InitHooks(&cJSON_hook);
【2】从源码可知,“cJSON_Createxxx”类型函数(cJSON_CreateObject、cJSON_CreateArray、cJSON_CreateStringArray等等)内部使用的是动态堆内存申请,使用完必须使用“cJSON_Delete”函数释放内存,否则导致内存泄漏。
【3】作者的测试程序“”使用的是系统“malloc”和“free”内存管理函数,个人觉得使用cJSON的“cJSON_malloc”和“cJSON_free”会更方便移植。
4.参考
【1】译文:https://blog.csdn.net/qq_36291381/article/details/83059629

浙公网安备 33010602011771号