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

posted @ 2019-06-05 23:18  Acuity  阅读(423)  评论(0)    收藏  举报