CJson源码解析之重要的数据结构cJSON
@TOC
前言
在现代编程中,JSON已经成为了一种非常流行的数据交换格式。它的简洁性和易读性使得开发者可以轻松地在不同的系统和应用之间共享和理解数据。CJson是一个轻量级的JSON解析库,它提供了一种简单和高效的方式来解析和生成JSON数据。本文将深入探讨CJson的源码,特别是它的核心数据结构cJSON。
cJSON结构体
结构体声明
对于CJson,他有一个很重要的结构体cJSON
,如下:
typedef struct cJSON
{
/* next/prev allow you to walk array/object chains. Alternatively, use GetArraySize/GetArrayItem/GetObjectItem */
struct cJSON *next;
struct cJSON *prev;
/* An array or object item will have a child pointer pointing to a chain of the items in the array/object. */
struct cJSON *child;
/* The type of the item, as above. */
int type;
/* The item's string, if type==cJSON_String and type == cJSON_Raw */
char *valuestring;
/* writing to valueint is DEPRECATED, use cJSON_SetNumberValue instead */
int valueint;
/* The item's number, if type==cJSON_Number */
double valuedouble;
/* The item's name string, if this item is the child of, or is in the list of subitems of an object. */
char *string;
} cJSON;
next,prev与child成员
在cJSON库中,next
,prev
和child
是用来表示JSON对象或数组的内部结构的。示例Json:
{
"A":10,
"B":true,
"C":"Hello World",
"D":[1,2,3,4],
"F":{
"AF":"AF"
}
}
在cJSON中,这个JSON对象会被表示为一个链表,其中每个键值对都是链表中的一个节点。每个节点都有next
和prev
成员,分别指向链表中的下一个和上一个节点。
例如,节点"A"的next
成员会指向节点"B",节点"B"的prev
成员会指向节点"A"。节点"F"的prev
成员会指向节点"D",而它的next
成员会是NULL
,因为它是链表的最后一个节点。
对于数组和嵌套的JSON对象,child
成员会被用来指向它们的第一个元素或键值对。例如,节点"D"的child
成员会指向它的第一个元素,即1。节点"F"的child
成员会指向它的第一个键值对,即"AF":“AF”。
那么数组就是这样:
"D": [1, 2, 3, 4]
这个数组会被表示为一个链表,其中每个元素都是链表中的一个节点。节点"D"的child成员会指向链表的第一个节点,即1。然后,1节点的next成员会指向下一个节点2,2节点的next成员会指向下一个节点3,以此类推,直到最后一个节点4,其next成员为NULL,表示它是链表的结束。同时,每个节点的prev成员会指向它的前一个节点,形成一个双向链表。
type成员
type成员是int
类型的,用来标识当前item是什么
他有下面这些取值:
#define cJSON_Invalid (0) /* 无效的JSON数据,例如:"" */
#define cJSON_False (1 << 0) /* JSON布尔值false,例如:"key": false */
#define cJSON_True (1 << 1) /* JSON布尔值true,例如:"key": true */
#define cJSON_NULL (1 << 2) /* JSON null值,例如:"key": null */
#define cJSON_Number (1 << 3) /* JSON数字,例如:"key": 10 */
#define cJSON_String (1 << 4) /* JSON字符串,例如:"key": "value" */
#define cJSON_Array (1 << 5) /* JSON数组,例如:"key": [1, 2, 3] */
#define cJSON_Object (1 << 6) /* JSON对象,例如:"key": {"subkey": "value"} */
#define cJSON_Raw (1 << 7) /* raw json,例如:"key": "{raw json string}" */
其他的很好理解,唯一迷惑的就是cJSON_Raw
和cJSON_String
不是一个玩意吗?
但是这是错误的理解。
cJSON_String代表了JSON字符串。例如,"key": "value"
中的"value"
就是一个JSON字符串。
cJSON_Raw则用于表示原始的JSON数据。这通常用于当你想直接插入一段未经处理的JSON数据到你的JSON对象或数组中。例如,"key": "{raw json string}"
中的"{raw json string}"
就是一个raw JSON数据。
那么什么又叫做未经处理的Json数据???
“未经处理的字符串"通常指的是原始的、未经任何修改或格式化的字符串。在JSON的上下文中,当我们说到"未经处理的JSON数据"或"原始的JSON数据”,我们指的是一段直接从源头获取的、未经任何解析或转换的JSON字符串。
例如,考虑以下的JSON字符串:
"{\"name\": \"John\", \"age\": 30, \"city\": \"New York\"}"
这就是一个"未经处理的字符串"或"原始的JSON数据"。它是一个完整的JSON对象,包含了"name"、"age"和"city"三个键,以及它们对应的值。这个字符串可以直接被JSON解析器解析,转换为一个JSON对象。简而言之就是普通的字符串,他可以被转换为Json对象,但没有转换之前的状态
相反,如果我们有一个字符串"John"
,并且我们想把它作为一个JSON字符串的一部分,我们需要对它进行处理,例如,将它包裹在引号中,转义必要的字符等,使得它能够被正确地解析为JSON的一部分。
数据成员
这些是cJSON库中的一些重要成员,它们在cJSON数据结构中存储了关于JSON数据的关键信息。以下是每个成员的详细介绍:
-
char *valuestring
:如果cJSON项的类型是cJSON_String
或cJSON_Raw
,那么valuestring
成员就会存储该项的字符串值。例如,在JSON数据{"key": "value"}
中,"value"就会被存储在valuestring
成员中。 -
int valueint
:这个成员已经被弃用,不推荐直接写入valueint
。如果需要设置一个cJSON项的数值,应该使用cJSON_SetNumberValue
函数。 -
double valuedouble
:如果cJSON项的类型是cJSON_Number
,那么valuedouble
成员就会存储该项的数值。例如,在JSON数据{"key": 10.5}
中,10.5就会被存储在valuedouble
成员中。 -
char *string
:如果一个cJSON项是一个对象的子项,或者是一个对象的子项列表中的一项,那么string
成员就会存储该项的名称。例如,在JSON数据{"key": "value"}
中,"key"就会被存储在string
成员中。
总结
通过深入研究CJson的源码,我们可以更好地理解JSON数据格式的内在工作原理,以及如何有效地解析和生成JSON数据。cJSON作为CJson的核心数据结构,它的设计和实现对于理解CJson的功能和性能至关重要。希望通过本文的阅读,你能对CJson有一个更深入的理解,也能在你的编程实践中更有效地使用JSON数据格式。未来,我们还将继续探索更多关于CJson的主题,包括它的性能优化,错误处理,以及如何在特定的应用场景中使用CJson。
- 点赞
- 收藏
- 关注作者
评论(0)