• cJSON使用说明


    一、包含头文件

    二、数据结构

     1 #include <cjson/cJSON.h>
     2 
     3 /* The cJSON structure: */
     4 typedef struct cJSON
     5 {
     6     struct cJSON *next;
     7     struct cJSON *prev;
     8     struct cJSON *child;
     9     int type;
    10     char *valuestring;
    11     /* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
    12     int valueint;
    13     double valuedouble;
    14     char *string;
    15 } cJSON;

       type:说明了JSON值的类型,位标识。

    通过以下方法检查元素类型:

     1 /* These functions check the type of an item */
     2 CJSON_PUBLIC(cJSON_bool) cJSON_IsInvalid(const cJSON * const item);
     3 CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
     4 CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
     5 CJSON_PUBLIC(cJSON_bool) cJSON_IsBool(const cJSON * const item);
     6 CJSON_PUBLIC(cJSON_bool) cJSON_IsNull(const cJSON * const item);
     7 CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
     8 CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
     9 CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
    10 CJSON_PUBLIC(cJSON_bool) cJSON_IsObject(const cJSON * const item);
    11 CJSON_PUBLIC(cJSON_bool) cJSON_IsRaw(const cJSON * const item);

     type的取值:

     1 /* cJSON Types: */
     2 #define cJSON_Invalid (0)
     3 #define cJSON_False  (1 << 0)
     4 #define cJSON_True   (1 << 1)
     5 #define cJSON_NULL   (1 << 2)
     6 #define cJSON_Number (1 << 3)
     7 #define cJSON_String (1 << 4)
     8 #define cJSON_Array  (1 << 5)
     9 #define cJSON_Object (1 << 6)
    10 #define cJSON_Raw    (1 << 7) /* raw json */
    11 
    12 #define cJSON_IsReference 256
    13 #define cJSON_StringIsConst 512

    cJSON_IsReference:表明子节点指向的条目或值串(valuestring)不属于此项目,它只是一个引用。cJSON_Delete和其他函数只会解除分配这个项目,而不是children/valuestring。

    cJSON_StringIsConst:表示该string指向一个常量string。表明cJSON_Delete和其他函数不能尝试释放该string。

    三、使用数据结构

     1 /* These calls create a cJSON item of the appropriate type. */
     2 CJSON_PUBLIC(cJSON *) cJSON_CreateNull(void);
     3 CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
     4 CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
     5 CJSON_PUBLIC(cJSON *) cJSON_CreateBool(cJSON_bool boolean);
     6 CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
     7 CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
     8 /* raw json */
     9 CJSON_PUBLIC(cJSON *) cJSON_CreateRaw(const char *raw);
    10 CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);
    11 CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);
    12 
    13 /* Create a string where valuestring references a string so
    14  * it will not be freed by cJSON_Delete */
    15 CJSON_PUBLIC(cJSON *) cJSON_CreateStringReference(const char *string);
    16 /* Create an object/arrray that only references it's elements so
    17  * they will not be freed by cJSON_Delete */
    18 CJSON_PUBLIC(cJSON *) cJSON_CreateObjectReference(const cJSON *child);
    19 CJSON_PUBLIC(cJSON *) cJSON_CreateArrayReference(const cJSON *child);
    20 
    21 /* These utilities create an Array of count items. */
    22 CJSON_PUBLIC(cJSON *) cJSON_CreateIntArray(const int *numbers, int count);
    23 CJSON_PUBLIC(cJSON *) cJSON_CreateFloatArray(const float *numbers, int count);
    24 CJSON_PUBLIC(cJSON *) cJSON_CreateDoubleArray(const double *numbers, int count);
    25 CJSON_PUBLIC(cJSON *) cJSON_CreateStringArray(const char **strings, int count);
    1. 基本类型
      1. 使用cJSON_CreateNull()创建null。
      2. 使用cJSON_CreateTrue(),cJSON_CreateFalse()或cJSON_CreateBool()创建布尔值。
      3. 使用cJSON_CreateNumber()创建数字这将设置valuedouble和valueint。INT_MAX或INT_MIN是valueint值的上下限。
      4. 使用cJSON_CreateString()(字符创拷贝)创建字符串,或cJSON_CreateStringReference(直接指向字符串。意味着valuestring不能直接被删除,你需要负责该对象的整个生命期)
    2. 数组
      1. 您可以使用创建一个空数组cJSON_CreateArray。cJSON_CreateArrayReference可用于创建不“拥有”其内容的数组,因此其内容不会被删除cJSON_Delete。
      2. cJSON_AddItemToArray()添加到末尾。cJSON_AddItemReferenceToArray(),将一个元素作为一个指向一个item、数组或字符串的引用。这意味着cJSON_Delete不会删除该项child或valuestring属性,因此如果已经在其他地方使用过,则不会发生双重释放。要在中间插入项目,请使用cJSON_InsertItemInArray。它将在给定的基于0的索引处插入项目,并将所有现有项目向右移动。
      3. 如果你想从一个给定索引的数组中取出一个项目并继续使用它,使用cJSON_DetachItemFromArray它将返回分离的项目,所以一定要把它分配给一个指针,否则你会有内存泄漏。
      4. cJSON_DeleteItemFromArray()完成删除条目。工作类似于cJSON_DetachItemFromArray,删除的条目会被cJSON_Delete删除。
      5. 删除条目,cJSON_ReplaceItemInArray通过下标删除,cJSON_ReplaceItemViaPointer通过指针删除。如果失败,cJSON_ReplaceItemViaPointer会返回0。cJSON_ReplaceItemViaPointer会分离item并删除它,然后在它的位置插入新的item.
      6. 使用cJSON_GetArraySize获取数组大小。使用cJSON_GetArrayItem获取一个元素,通过一个给定的下标。
      7. 因为数组是以链表存储的,通过下标进行迭代是低效的(O(n2)),因此可以使用宏cJSON_ArrayForEach来对一个数组进行迭代,其时间复杂度为O(n)。
    3. 对象
      1. 您可以使用创建一个空对象cJSON_CreateObject。cJSON_CreateObjectReference可用于创建不“拥有”其内容的对象,因此其内容不会被删除cJSON_Delete。
      2. 使用cJSON_AddItemToObject为对象增加一个item。使用cJSON_AddItemToObjectCS将一个常量或引用(JSON结构中的item键值,字符串)作为item添加给对象,因此其不会通过cJSON_delete删除。使用cJSON_AddItemReferenceToArray,一个元素会被作为其他对象、数组或字符串的引用添加。这意味着cJSON_Delete不会删除该item的child或valuestring属性。因此不用担心双重释放。
      3. 使用cJSON_DetachItemFromObjectCaseSensitive从一个对象中删除一个item。他会分离item,因此要保证分配一个指针,否则会内存泄漏。
      4. cJSON_DeleteItemFromObjectCaseSensitive会完成删除item。他工作类似于cJSON_DetachItemFromObjectCaseSensitive后调用了cJSON_Delte。
      5. cJSON_ReplaceItemInObjectCaseSensitive使用一个键值,cJSON_ReplaceItemViaPointer使用一个指向元素的指针,删除对象中的item。如果失败,cJSON_ReplaceItemViaPointer返回0。内部原理是分离旧的item,删除它,返回在它的位置插入新的item。
      6. 通过cJSON_GetArraySize获取对象的size。他能生效,是因为,对象在内部被存储为数组。
      7. 使用cJSON_GetObjectItemCaseSensitive访问对象中的item。
      8. 要迭代对象,你可像数组一样使用宏cJSON_ArrayForEach
      9. cJSON提供了很多方便的帮助函数,能快速的创建一个item,并将其添加到对象,如cJSON_AddNullToObject。他们返回指向新item的指针或者null。

    四、解析JSON

      对于给定包含0终止符的字符串,你可使用cJSON_Parse解析它:

    1 cJSON *json = cJSON_Parse(string);

      它解析JSON,并分配一个cJSON树来表示它。一旦返回,你完全有责任在使用后调用cJSON_Delete。

      通过所使用的分配器cJSON_Parse默认使用malloc和free,但可以用cJSON_InitHooks改变(全局)。

      当一个错误发生,使用cJSON_GetErrorPtr可以访问,指向输入字符串的错误位置的指针。(原文:If an error occurs a pointer to the position of the error in the input string can be accessed using cJSON_GetErrorPtr. )请注意,这可以产生多线程情况下的竞争条件,在这种情况下,最好是使用cJSON_ParseWithOpts带有return_parse_end默认情况下,输入字符串中跟随解析的JSON的字符不会被视为错误。

      如果您想要更多选项,请使用cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)。 return_parse_end返回指向输入字符串中JSON末尾的指针或发生错误的位置(从而以cJSON_GetErrorPtr线程安全方式替换)。require_null_terminated,如果设置为1将在输入字符串包含JSON之后的数据时使其成为错误。

      注:cJSON_InitHooks和cJSON_GetErrorPtr是cjson线程不安全的几个原因之二。

    五、打印JSON

      给定一个CJSON树,可以使用cJSON_Print打印:

    1 char *string = cJSON_Print(json);

       它将分配一个字符串并将树的JSON表示形式打印到其中。一旦它返回,您完全有责任在使用分配器后解除分配。(通常free取决于设定的内容cJSON_InitHooks)。

      cJSON_Print将使用空格打印以进行格式化。如果要打印而不进行格式化,请使用cJSON_PrintUnformatted。

      如果您大致了解结果字符串的大小,可以使用cJSON_PrintBuffered(const cJSON *item, int prebuffer, cJSON_bool fmt)。fmt是一个布尔值,用于打开和关闭空格的格式。prebuffer指定用于打印的第一个缓冲区大小。cJSON_Print目前使用256个字节作为它的第一个缓冲区大小。一旦打印空间不足,就会分配一个新的缓冲区,并在继续打印之前复制旧的缓冲区。

      使用可以完全避免这些动态缓冲区分配cJSON_PrintPreallocated(cJSON *item, char *buffer, const int length, const cJSON_bool format)。它需要一个缓冲区来指向要打印的指针和它的长度。如果达到长度,打印将失败并返回0。如果成功,1则返回。请注意,您应该提供比实际需要多5个字节,因为cJSON在估计提供的内存是否足够时不是100%准确。

    六、例子

      在例子中,我们要建立并解析下面的JSON:

     1 {
     2     "name": "Awesome 4K",
     3     "resolutions": [
     4         {
     5             "width": 1280,
     6             "height": 720
     7         },
     8         {
     9             "width": 1920,
    10             "height": 1080
    11         },
    12         {
    13             "width": 3840,
    14             "height": 2160
    15         }
    16     ]
    17 }

     打印

     建立上面的JSON并打印为字符串。

     1 //create a monitor with a list of supported resolutions
     2 char* create_monitor(void)
     3 {
     4     const unsigned int resolution_numbers[3][2] = {
     5         {1280, 720},
     6         {1920, 1080},
     7         {3840, 2160}
     8     };
     9     char *string = NULL;
    10     cJSON *name = NULL;
    11     cJSON *resolutions = NULL;
    12     cJSON *resolution = NULL;
    13     cJSON *width = NULL;
    14     cJSON *height = NULL;
    15     size_t index = 0;
    16 
    17     cJSON *monitor = cJSON_CreateObject();
    18     if (monitor == NULL)
    19     {
    20         goto end;
    21     }
    22 
    23     name = cJSON_CreateString("Awesome 4K");
    24     if (name == NULL)
    25     {
    26         goto end;
    27     }
    28     /* after creation was successful, immediately add it to the monitor,
    29      * thereby transfering ownership of the pointer to it */
    30     cJSON_AddItemToObject(monitor, "name", name);
    31 
    32     resolutions = cJSON_CreateArray();
    33     if (resolutions == NULL)
    34     {
    35         goto end;
    36     }
    37     cJSON_AddItemToObject(monitor, "resolutions", resolutions);
    38 
    39     for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    40     {
    41         resolution = cJSON_CreateObject();
    42         if (resolution == NULL)
    43         {
    44             goto end;
    45         }
    46         cJSON_AddItemToArray(resolutions, resolution);
    47 
    48         width = cJSON_CreateNumber(resolution_numbers[index][0]);
    49         if (width == NULL)
    50         {
    51             goto end;
    52         }
    53         cJSON_AddItemToObject(resolution, "width", width);
    54 
    55         height = cJSON_CreateNumber(resolution_numbers[index][1]);
    56         if (height == NULL)
    57         {
    58             goto end;
    59         }
    60         cJSON_AddItemToObject(resolution, "height", height);
    61     }
    62 
    63     string = cJSON_Print(monitor);
    64     if (string == NULL)
    65     {
    66         fprintf(stderr, "Failed to print monitor.
    ");
    67     }
    68 
    69 end:
    70     cJSON_Delete(monitor);
    71     return string;
    72 }

      另外,我们使用cJSON_Add...ToObject帮助函数使我们的生活更轻松(^-^):

     1 char *create_monitor_with_helpers(void)
     2 {
     3     const unsigned int resolution_numbers[3][2] = {
     4         {1280, 720},
     5         {1920, 1080},
     6         {3840, 2160}
     7     };
     8     char *string = NULL;
     9     cJSON *resolutions = NULL;
    10     size_t index = 0;
    11 
    12     cJSON *monitor = cJSON_CreateObject();
    13 
    14     if (cJSON_AddStringToObject(monitor, "name", "Awesome 4K") == NULL)
    15     {
    16         goto end;
    17     }
    18 
    19     resolutions = cJSON_AddArrayToObject(monitor, "resolutions");
    20     if (resolutions == NULL)
    21     {
    22         goto end;
    23     }
    24 
    25     for (index = 0; index < (sizeof(resolution_numbers) / (2 * sizeof(int))); ++index)
    26     {
    27         cJSON *resolution = cJSON_CreateObject();
    28 
    29         if (cJSON_AddNumberToObject(resolution, "width", resolution_numbers[index][0]) == NULL)
    30         {
    31             goto end;
    32         }
    33 
    34         if(cJSON_AddNumberToObject(resolution, "height", resolution_numbers[index][1]) == NULL)
    35         {
    36             goto end;
    37         }
    38 
    39         cJSON_AddItemToArray(resolutions, resolution);
    40     }
    41 
    42     string = cJSON_Print(monitor);
    43     if (string == NULL) {
    44         fprintf(stderr, "Failed to print monitor.
    ");
    45     }
    46 
    47 end:
    48     cJSON_Delete(monitor);
    49     return string;
    50 }

    解析

    在此例中,我们会以上面的格式解析一个JSON,并在打印诊断输出时检查monitor是否为一个full HD resolution。

     1 /* return 1 if the monitor supports full hd, 0 otherwise */
     2 int supports_full_hd(const char * const monitor)
     3 {
     4     const cJSON *resolution = NULL;
     5     const cJSON *resolutions = NULL;
     6     const cJSON *name = NULL;
     7     int status = 0;
     8     cJSON *monitor_json = cJSON_Parse(monitor);
     9     if (monitor_json == NULL)
    10     {
    11         const char *error_ptr = cJSON_GetErrorPtr();
    12         if (error_ptr != NULL)
    13         {
    14             fprintf(stderr, "Error before: %s
    ", error_ptr);
    15         }
    16         status = 0;
    17         goto end;
    18     }
    19 
    20     name = cJSON_GetObjectItemCaseSensitive(monitor_json, "name");
    21     if (cJSON_IsString(name) && (name->valuestring != NULL))
    22     {
    23         printf("Checking monitor "%s"
    ", name->valuestring);
    24     }
    25 
    26     resolutions = cJSON_GetObjectItemCaseSensitive(monitor_json, "resolutions");
    27     cJSON_ArrayForEach(resolution, resolutions)
    28     {
    29         cJSON *width = cJSON_GetObjectItemCaseSensitive(resolution, "width");
    30         cJSON *height = cJSON_GetObjectItemCaseSensitive(resolution, "height");
    31 
    32         if (!cJSON_IsNumber(width) || !cJSON_IsNumber(height))
    33         {
    34             status = 0;
    35             goto end;
    36         }
    37 
    38         if ((width->valuedouble == 1920) && (height->valuedouble == 1080))
    39         {
    40             status = 1;
    41             goto end;
    42         }
    43     }
    44 
    45 end:
    46     cJSON_Delete(monitor_json);
    47     return status;
    48 }

    注意cJSON_Parse的结果没有检查NULL,因为cJSON_GetObjectItemCaseSensitive已经检查过。因此如果输入为NULL,NULL值会被传递,cJSON_IsNumber 和cJSON_IsString返回0。

    七、注意事项

    1. 零字符
      1. cJSON不支持字符串包含零字符,如‘'或u0000。这是不可能出现的,因为字符串是以0结尾的。
    2. 字符编码
      1. cJSON只支持UTF-8编码输入。在大多数情况下,它不会拒绝无效的UTF-8,它只是按原样传递。只要输入不包含无效的UTF-8,输出将始终是有效的UTF-8。
    3. C标准
      1. cJSON是使用ANSI C(or C89, C90)编写的。如果你的编译器和C库不遵循此标准,将无法确保正确的行为。
      2. ANSI C不是C++,因此它不应被C++编译器编译。你可以使用C编译器编译它,然后链接到你的C++代码。尽管C++编译的代码能工作,但无法保证正确的行为。
    4. 浮点数
      1. cJSON不正式支持doubleIEEE754双精度浮点数以外的任何实现。它可能仍然适用于其他实现,但这些错误将被视为无效

      2. cJSON支持的浮点文字的最大长度目前为63个字符。
    5. 数组和对象的深度嵌套
      1. cJSON不支持嵌套太深的数组和对象,因为这会导致堆栈溢出。为了防止此cJSON默认限制深度CJSON_NESTING_LIMIT为1000,但可以在编译时更改。
    6. 线程安全

      通常,cJSON不是线程安全的。但在以下情况下是线程安全的。

    1 cJSON_GetErrorPtr 没有被调用过。可使用cJSON_ParseWithOpts 的参数return_parse_end 替代。
    2 cJSON_InitHooks 仅仅在任何线程使用cJSON之前调用。
    3 setlocale不在所有的cJSON函数返回前被调用。

      7.区分大小写

        最初创建cJSON时,它未遵循JSON标准,并未区分大小写字母。如果您需要正确的,符合标准的行为,则需要使用CaseSensitive可用功能。

      8.重复对象成员

        cJSON支持解析和打印包含具有多个具有相同名称的成员的对象的JSON。cJSON_GetObjectItemCaseSensitive但总是只返回第一个。

    备注:

    1. 该文来自cJSON项目官方文档中部分内容,中文翻译参考谷歌翻译。https://github.com/DaveGamble/cJSON
    2. 官方推荐使用cmake来构建整个项目。可用make install,默认安装头/usr/local/include/cjson和库/usr/local/lib 
    3. 官方不推荐使用Makefile。运行make all,make install安装路径头/usr/local/include/cjson和库中的/usr/local/lib。可以通过设置PREFIX和DESTDIR变量来更改:make PREFIX=/usr DESTDIR=temp install。
    4. 关于对多线程的支持,可通过代码设计规范来实现。
  • 相关阅读:
    第九章 ZYNQ-MIZ701 片上ADC的使用
    第八章 ZYNQ-MIZ701 软硬调试高级技巧
    第七章 ZYNQ-MIZ701 GPIO使用之EMIO
    第六章 ZYNQ-MIZ701 GPIO使用之MIO
    第十章 MIZ702 ZYNQ制作UBOOT固化程序
    bzoj1070 [SCOI2007]修车
    bzoj1449 [JSOI2009]球队收益
    bzoj2007 [Noi2010]海拔
    bzoj1001 [BeiJing2006]狼抓兔子
    网络流的一类经典问题--二元费用问题
  • 原文地址:https://www.cnblogs.com/mofei004/p/9668132.html
Copyright © 2020-2023  润新知