cJSON库学习——C语言结构体与JSON互相转换

跟着这两个教程学习的:

https://www.cnblogs.com/young525/p/5873783.html

https://www.jianshu.com/p/59eb2bd1aeea

cJSON是一个公开库,一共两个文件,分别是是cJSON.c和cJSON.h,链接如下:

​​​​​​https://github.com/DaveGamble/cJSON

顾名思义,这个库的主要目的就是往C语言中引入JSON的数据结构,下面给一段示例的代码片段:

#include <stdio.h>
#include "cJSON.h"

int main() {
    //JSON本质上就是键值对,所以JSON在C语言中的表现形式就是键值对组成的字符串
    //字符串需要加双引号,所有的键默认为字符串
    //一共定义了7种类型,可以查看cJSON.h中的cJSON Types这一行了解
    //以下为两种JSON字符串的常见形式
    //普通JSON
    /*{ "json" : { 
                    "id":1, 
                    "nodeId":11, 
                    "deviceId":111, 
                    "deviceName":"aaa", 
                    "ieee":"01212", 
                    "ep":"1111", 
                    "type":"bbb" 
                  }
       }
    //加入了数组的JSON
      {  "id":[1,2,3,4,5], 
         "nodeId":11, 
         "deviceId":111, 
         "deviceName":"aaa"
       }
    */
    char* json1 = "{ \"json\" : { \"id\":1, \"nodeId\":11, \"deviceId\":111, \"deviceName\":\"aaa\", \"ieee\":\"01212\", \"ep\":\"1111\", \"type\":\"bbb\" }}";
    char* json2 = "{\"id\":[1,2,3,4,5], \"nodeId\":11, \"deviceId\":111, \"deviceName\":\"aaa\"}";
    cJSON* root;
    cJSON* format;
    cJSON* array;
    int value_int;
    int array_len;
    int i = 0;
    char* value_string;

    //解析json1
    //通过cJSON_Parse解析接收到的字符串,再通过cJSON_GetObjectItem获取指定键的值,最后释放该JSON结点的内存
    root = cJSON_Parse(json1);
    format = cJSON_GetObjectItem(root, "json");
    value_int = cJSON_GetObjectItem(format, "nodeId")->valueint;
    value_string = cJSON_GetObjectItem(format, "ieee")->valuestring;
    printf("%d\n", value_int);
    printf("%s\n", value_string);
    cJSON_Delete(root);

    //解析json2
    //添加了数组解析
    root = cJSON_Parse(json2);
    //数组解析
    array = cJSON_GetObjectItem(root, "id");//获取数组的根节点
    value_int = cJSON_GetArraySize(array);//获取数组长度
    printf("数组长度为:%d\n", value_int);
    //循环打印数组的内容
    for (i = 0; i < value_int; i++) {
        value_int = cJSON_GetArrayItem(array, i)->valueint;//获取数组下标为i的数据,以int形式解析
        printf("第%d个元素为:%d\n",i+1,value_int);
    }
    value_string = cJSON_GetObjectItem(root, "deviceName")->valuestring;
    printf("%s\n", value_string);
    cJSON_Delete(root);

    return 0;
}

运行结果:

 

该代码展示了​如何将一段以字符串形式表示的JSON串转换为cJSON的结构并进行解析,接下来是如何通过代码创建cJSON结构体:

#include <stdio.h>
#include "cJSON.h"


int main() {
    //通过cJSON_CreateObject创建根节点,通过cJSON_CreateArray创建数组
    //通过cJSON_AddItemToObject向一个节点添加元素,通过cJSON_AddItemToArray向数组添加元素
    cJSON* pRoot = cJSON_CreateObject();
    cJSON* pArray = cJSON_CreateArray();
    cJSON_AddItemToObject(pRoot, "students_info", pArray);

    cJSON* pItem = cJSON_CreateObject();
    cJSON_AddStringToObject(pItem, "name", "chenzhongjing");
    cJSON_AddStringToObject(pItem, "sex", "male");
    cJSON_AddNumberToObject(pItem, "age", 28);
    cJSON_AddItemToArray(pArray, pItem);

    pItem = cJSON_CreateObject();
    cJSON_AddStringToObject(pItem, "name", "fengxuan");
    cJSON_AddStringToObject(pItem, "sex", "male");
    cJSON_AddNumberToObject(pItem, "age", 24);
    cJSON_AddItemToArray(pArray, pItem);

    pItem = cJSON_CreateObject();
    cJSON_AddStringToObject(pItem, "name", "tuhui");
    cJSON_AddStringToObject(pItem, "sex", "male");
    cJSON_AddNumberToObject(pItem, "age", 22);
    cJSON_AddItemToArray(pArray, pItem);

    char* szJSON = cJSON_Print(pRoot);//通过cJSON_Print获取cJSON结构体的字符串形式(注:存在\n\t)
    printf(szJSON);
    cJSON_Delete(pRoot);

    free(szJSON);
    return 0;
}

运行结果:

 

要注意的是产生的字符串中存在较多的\n与\t,如果不需要的话需要后期进行处理。

 

通过这两段代码,就可以借助cJSON库来实现字符串与cJSON结构体的互相转换。C语言结构体与JSON可以通过cJSON结构体来进行中转,从而实现之间的转换。以下为一个范例:

#include <stdio.h>
#include "cJSON.h"

typedef struct _c_struct_t{
    unsigned char a;
    unsigned short b;
    unsigned int c;
    unsigned long long d;
    float e;
}c_struct_t;

int main() {
    //创建JSON串:{"uint_8":8,"uint_16":16,"uint_32":32,"uint_64":64,"float":6.13141516}
    //其中float格式故意越界初始化
    c_struct_t testStruct1 = { 255,16,32,64,6.13141516 };
    c_struct_t testStruct2 = { 0 };
    cJSON* pRoot = cJSON_CreateObject();
    cJSON_AddNumberToObject(pRoot, "uint_8", testStruct1.a);
    cJSON_AddNumberToObject(pRoot, "uint_16", testStruct1.b);
    cJSON_AddNumberToObject(pRoot, "uint_32", testStruct1.c);
    cJSON_AddNumberToObject(pRoot, "uint_64", testStruct1.d);
    cJSON_AddNumberToObject(pRoot, "float", testStruct1.e);
    char* szJSON = cJSON_Print(pRoot);//通过cJSON_Print获取cJSON结构体的字符串形式(注:存在\n\t)
    printf(szJSON);
    printf("\n");

    cJSON* root = cJSON_Parse(szJSON);
    testStruct2.a = cJSON_GetObjectItem(root, "uint_8")->valueint;
    testStruct2.b = cJSON_GetObjectItem(root, "uint_16")->valueint;
    testStruct2.c = cJSON_GetObjectItem(root, "uint_32")->valueint;
    testStruct2.d = cJSON_GetObjectItem(root, "uint_64")->valueint;
    testStruct2.e = cJSON_GetObjectItem(root, "float")->valuedouble;

    printf("%u\n%u\n%u\n%llu\n%f\n", testStruct2.a, testStruct2.b, testStruct2.c, testStruct2.d, testStruct2.e);

    return 0;
}

运行结果:

 

 可以看到float格式存储的数据从6.13141516变成了这么一长串的数字,实际上在赋值后数值为6.13141537。这就是单精度的存储范围问题,以及单精度双精度转换的问题。在CJSON结构体中存储数值时时以int格式存储的,所以会产生这样的问题。而在转换为结构体中的float时,由于精度问题,只保留到小数点后第6位。

代码中可以看到无论cJSON结构体的解析还是封装都是挨个书写的,这主要还是因为c语言中没有反射机制,自己写反射机制有点难。所以目前以我的水平只能写成这样,一种结构体一种转换函数。

 

以上。

 

posted @ 2022-03-27 18:14  熊叔  阅读(6090)  评论(0编辑  收藏  举报