【源码分析】cJSON库学习
cJSON库是什么?
cJSON是一个轻量级的json解析库。使用起来非常简单,整个库非常地简洁,核心功能的实现都在cJSON.c文件,非常适合阅读源代码来学习C语言。最近读完这个库的源码,分享自己收获的一些心得。
什么是json,照搬json官网的说法:
JSON(JavaScript Object Notation) 是一种轻量级的数据交换格式。 易于人阅读和编写。同时也易于机器解析和生成。 它基于JavaScript Programming Language, Standard ECMA-262 3rd Edition - December 1999的一个子集。 JSON采用完全独立于语言的文本格式,但是也使用了类似于C语言家族的习惯(包括C, C++, C#, Java, JavaScript, Perl, Python等)。 这些特性使JSON成为理想的数据交换语言。
cJSON库里面有什么?
cjson库github地址:https://github.com/DaveGamble/cJSON
整个库包含cJSON.h和cJSON.c两个文件,头文件定义了一系列的API。这个库最基本也最重要的功能就是解析一个json字符串,使用的API是cJSON_Parse。cJSON_Parse函数调用了cJSON_ParseWithOpts函数,该函数实现了具体的逻辑。
两个函数的原型如下:
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);
CJSON_PUBLIC(cJSON *) cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated);
函数接收一段字符串,然后进行解析后返回。解析完返回的是一个cjson结构,cJSON结构的定义如下:
typedef struct cJSON
{
struct cJSON *next; // 向后指针
struct cJSON *prev; // 向前指针
struct cJSON *child; // 指向子元素,比如子数组或者子对象
int type; // 元素的类型
char *valuestring; // 元素的字符串值,如果type == cJSON_String 或者 type == cJSO_Raw
int valueint; // 已废弃,现在使用cJSON_SetNumberValue设置整型值
double valuedouble; // 元素的整型值,如果type == cJSON_Number
char *string; // 表示元素键值的值,如果它有子元素的话
} cJSON;
如何解析一个json字符串?
json的官网在这里,http://www.json.org
网站首页描述了json是什么以及它的格式规范,有了规范之后,可以知道json是如何构成的,因此就有了如何解析json数据的方向。
json使用两种结构构建,对象或者数组。
对象使用{
作开头,}
作结尾,里边的每一个元素都是键值对的无序集合,键名和值使用:
分隔,使用,
分隔每一个元素;数组使用[作开头,]作结尾,里面的元素都是有序的值组成的集合,且使用,
做分隔符。
每一个值可以是字符串,整型,也可以是true,false,null等常量,还可以是对象或数组,因为json结构是可嵌套的。
因此,我们可以得知:
1、可以根据json的首字母判断整个json的类型,如果json以'{'
开头时,就是对象,以'['
开头时,就是数组,否则就是字符串或者其他常量。
2、如果是对象,那么它的一定有键名,先解析它的键名,然后解析它的值,解析值的过程与第一步一样,递归解析
3、如果是数组,则逐个解析数组内的元素,直到遇到]
为止,解析数组里面的元素的过程也是与第一步一致,递归解析。
这就是根据json官网的定义得出解析json字符串的思路,接下来看看cJSON库是如何实现的。cJSON_Parse的实现流程图如下:
cJSON_ParseWithOpts函数里面调用了parse_value,是整个函数的核心实现。
parse_value函数的流程图如下所示:
可以看到,parse_value是对json值的开头进行判断,然后进入相应的分支进行解析,下面对每一个分支进行分析。解析出来的值是保存在cJSON的结构体中,以下命名为item。
常量
如果json值是以'null','true','false',则分别将item的type设置为cJSON_NULL、cJSON_TRUE、cJSON_FALSE。然后继续解析剩下的json值。
string
如果遇到"开头,则说明json值是字符串,就解析它的值,此时只需要拿到两个"之间的值即可。保存字符串也是一个结构体,需要申请内存,计算长度的过程中,当遇到转义字符时,需要记录,因为转义符不保存。
number
当遇到数字开头时,将其后面的数字字符记录起来,然后转成整型数字,然后做值的范围检查。
array
解析数组时,为数组的元素创建一个新的json结构体new_item,然后继续解析数组里面的值,用','判断下一个元素的位置,得到的值保存到结构体中,并将多个元素用链表连接起来。一直解析,直到遇到']'符号。
object
解析对象的过程与数组的类似,为对象的元素创建一个新的json结构体new_item,然后继续解析对象里面的值,对象是有键值对组成的,因此先得到键的值,然后用':'判断值的位置,进而继续解析得到值,多个键值对之间用','分隔开,最后用链表连接起来。一直解析,直到遇到'}'符号。
其他
在解析所有值之前,会调用skip_whitespace函数过滤字符串两边的所有空白字符。此处是ASCII码小于等于32的字符,如:\t、\n。函数如下:
static const unsigned char *skip_whitespace(const unsigned char *in)
{
while (in && *in && (*in <= 32))
{
in++;
}
return in;
}
总结
通过阅读这个小小的json解析库,知道了大部分的json库是如何实现的,自己对json的认识也有了一个更深刻的印象。
学习到了一种解析某种格式的字符串的思路,要先知道该字符串格式的规范,直到它是如何组成的,有哪些规则和注意的地方,从它的组成规范中逐步分解和解析。
【源码分析】cJSON库学习的更多相关文章
- [转]数据库中间件 MyCAT源码分析——跨库两表Join
1. 概述 2. 主流程 3. ShareJoin 3.1 JoinParser 3.2 ShareJoin.processSQL(...) 3.3 BatchSQLJob 3.4 ShareDBJo ...
- JDK1.8源码分析01之学习建议(可以延伸其他源码学习)
序言:目前有个计划就是准备看一下源码,来提升自己的技术实力.同时现在好多面试官都喜欢问源码,问你是否读过JDK源码等等? 针对如何阅读源码,也请教了我的老师.下面就先来看看老师的回答,也许会有帮助呢. ...
- Java源码——HashMap的源码分析及原理学习记录
学习HashMap时,需要带着这几个问题去,会有很大的收获: 一.什么是哈希表 二.HashMap实现原理 三.为何HashMap的数组长度一定是2的次幂? 四.重写equals方法需同时重写hash ...
- quagga源码分析--通用库thread
quagga是开源路由器软件,提供的用户界面与思科,华为的路由器的人机接口几乎一致,非常有学习价值,尤其是开源的协议代码,简直亮瞎了我的小眼睛. quagga的介绍,我就不赘述了,有兴趣的可以找度娘或 ...
- quagga源码分析--通用库command
quagga作为一个路由器软件,自然要提供人机接口. quagga提供snmp管理接口,而且,自然就会有对应的命令行管理格式,当然一般路由软件不会提供界面形式的,也许有webui,然而quagga并没 ...
- WCP源码分析 与SpringMVC学习资料
1.在一个稍大的项目中,通常会有上百个组件,如果这些组件采用xml的bean定义来配置,显然会增加配置文件的体积,查找以及维护起来也不太方便. Spring2.5为我们引入了组件自动扫描机制,他可以在 ...
- cJSON源码分析
JSON (JavaScript Object Notation) 是一种常见使用的轻量级的数据交换格式,既有利于人工读写,也方便于机器的解析和生成. 关于JSON格式的定义,参看网站[1].在该网站 ...
- OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波
http://blog.csdn.net/chenyusiyuan/article/details/8710462 OpenCV学习笔记(27)KAZE 算法原理与源码分析(一)非线性扩散滤波 201 ...
- DotNetty网络通信框架学习之源码分析
DotNetty网络通信框架学习之源码分析 有关DotNetty框架,网上的详细资料不是很多,有不多的几个博友做了简单的介绍,也没有做深入的探究,我也根据源码中提供的demo做一下记录,方便后期查阅. ...
- 比特币源码分析--C++11和boost库的应用
比特币源码分析--C++11和boost库的应用 我们先停下探索比特币源码的步伐,来分析一下C++11和boost库在比特币源码中的应用.比特币是一个纯C++编写的项目,用到了C++11和bo ...
随机推荐
- 超级素数幂 java
链接:https://www.nowcoder.com/questionTerminal/fb511c3f1ac447309368d7e5432c6c79来源:牛客网如果一个数字能表示为p^q(^表示 ...
- Android之万能播放器解码框架Vitamio的介绍及使用
一.简介 Vitamio能够流畅播放720P甚至1080P高清MKV,FLV,MP4,MOV,TS,RMVB等常见格式的视频,还可以在Android 与 iOS 上跨平台支持 MMS, RTSP, R ...
- Android学习探索之本地原生渲染 LaTeX数据公式
前言: 一直致力于为公司寻找更加高效的解决方案,作为一款K12在线教育App,功能中难免会有LaTeX数学公式的显示需求,这部分公司已经实现了此功能,只是个人觉得在体验和效率上还是不太好,今天来聊一下 ...
- 说说API的防重放机制
说说API的防重放机制 我们在设计接口的时候,最怕一个接口被用户截取用于重放攻击.重放攻击是什么呢?就是把你的请求原封不动地再发送一次,两次...n次,一般正常的请求都会通过验证进入到正常逻辑中,如果 ...
- JetBrains套装免费学生授权申请(IntelliJ, WebStorm...)
IntelliJ作为一款强大的Java开发IDE,售价自然也不会低.但是对于学生或教师来说,JetBrains开发工具免费提供给学生和教师使用.而且取得一次授权后只需要使用相同的 JetBrains ...
- Windows搭建以太坊的私有链环境
1.下载Geth.exe 运行文件,并安装 https://github.com/ethereum/go-ethereum/releases/ 下载后,只有一个Geth.exe的文件 2.cmd进入按 ...
- Jmeter-元件的作用域和执行顺序
Jmeter有8类可执行的元件,包括:逻辑控制器.配置元件.定时器.前置处理器.取样器.后置处理器.断言和监听器. 测试计划和线程组不属于元件. 1)取样器(Sampler):不与其他元件发生交互作用 ...
- vue的使用总结
1.vue的生命周期
- jenkins+SVN配置
开发项目,版本控制必不可少,我用的版本控制软件为SVN,那么如何把jenkins和SVN结合,使得SVN源码一有上传更新,jenkins就马上构建项目呢?下面说一下配置过程 1) ...
- rancher api key
rancher将docker容器的界面化做的很好了,但是我们有时间需要在别的地方查看容器的一些信息,怎么办呢? rancher自己提供的有api 点击api查看 我们能够查看到该容器的一些信息,实际上 ...