新闻详情

新闻详情

首页 / 资讯中心 / 详情

cJSON 源码解析:parse_string 函数深入剖析

发布时间:2026/10/1 20:30:10来源:尧图网络
cJSON 源码解析:parse_string 函数深入剖析
1. 引言cJSON 是一个轻量级的 C 语言 JSON 解析库因其代码简洁、无外部依赖而广受欢迎。在 cJSON 的解析流程中parse_string函数负责将 JSON 字符串字面量如hello、a\\nb解析为 C 字符串是整个解析器中最核心、也最容易出错的环节之一。本文将逐行剖析 cJSON 源码中的parse_string实现讲解其转义字符处理、Unicode 解码、内存分配等关键细节帮助你彻底理解这个函数的工作原理。2. parse_string 函数概览parse_string函数定义在cJSON.c文件中其函数签名如下staticcJSON_boolparse_string(cJSON*item,constunsignedchar*constinput,constunsignedchar**ep);三个参数的含义item指向待填充的 cJSON 节点解析成功后字符串值会存入item-valuestring。input指向 JSON 文本中字符串的起始位置即开头的双引号。ep指向指针的指针解析失败时用于记录错误位置。函数返回cJSON_bool即int成功返回true失败返回false。3. 整体流程parse_string的整体流程可以概括为以下几个步骤否是检查开头引号是否含转义字符?直接计算长度并复制逐字符解析转义处理 Unicode 转义分配内存并填充写入 valuestring更新解析位置 ep下面我们按照源码顺序逐步拆解每个环节。4. 源码逐段解析4.1 前置检查确认起始引号if(inputNULL||*input!\){returnfalse;}函数首先检查input是否为空以及当前位置是否为双引号。如果不是直接返回false表示解析失败。这是字符串解析的入口校验。4.2 第一遍扫描计算字符串长度constunsignedchar*pointerinput1;size_tlength0;while(*pointer!\*pointer!\0){if(*pointer\\){pointer;if(*pointer\0){returnfalse;}pointer;}else{pointer;}length;}这一遍扫描的目的是计算字符串的实际长度不含转义符本身。注意遇到\时跳过转义符及其后面的一个字符如\n、\都算一个字符。遇到或字符串结束符\0时停止。如果遇到\后紧跟\0说明转义不完整返回false。这里有个细节length统计的是转义后的字符数而不是原始字节数。例如a\\nb的原始字节数是 5a、\、n、b、但转义后实际只有 3 个字符a、换行、b。4.3 判断是否需要二次扫描if(*pointer!\){returnfalse;}第一遍扫描结束后pointer应指向结束引号。如果不是说明字符串没有正常闭合返回false。if(pointerinput1){/* 空字符串 */item-valuestring(char*)cJSON_malloc(1);if(item-valuestringNULL){returnfalse;}item-valuestring[0]\0;*eppointer1;returntrue;}如果pointer input 1说明字符串是空的直接分配 1 字节内存存放\0即可。if(length(size_t)(pointer-input)-1){/* 没有转义字符直接复制 */item-valuestring(char*)cJSON_malloc(length1);if(item-valuestringNULL){returnfalse;}memcpy(item-valuestring,input1,length);item-valuestring[length]\0;*eppointer1;returntrue;}这里是一个性能优化如果length不小于原始字节数减一即没有转义字符被压缩说明字符串中没有转义序列可以直接用memcpy批量复制无需逐字符处理。4.4 第二遍扫描处理转义字符/* 有转义字符需要逐字符处理 */pointerinput1;unsignedchar*output(unsignedchar*)cJSON_malloc(length1);if(outputNULL){returnfalse;}while(*pointer!\*pointer!\0){if(*pointer!\\){*output*pointer;}else{pointer;switch(*pointer){caseb:*output\b;break;casef:*output\f;break;casen:*output\n;break;caser:*output\r;break;caset:*output\t;break;case\:*output\;break;case\\:*output\\;break;case/:*output/;break;caseu:/* Unicode 转义稍后详解 */...default:cJSON_free(output);returnfalse;}pointer;}}第二遍扫描逐字符处理普通字符直接复制。遇到\时根据后面的字符进行转义映射。支持的标准转义\b、\f、\n、\r、\t、\、\\、\/、\uXXXX。遇到未知转义如\x释放内存并返回false。4.5 Unicode 转义处理caseu:/* 解析 4 位十六进制 Unicode 码点 */if(parse_hex4(pointer1,uc)){/* 处理代理对 */if((uc0xD800)(uc0xDBFF)(*(pointer5)\\)(*(pointer6)u)){unsignedshortuc20;if(parse_hex4(pointer7,uc2)){if((uc20xDC00)(uc20xDFFF)){/* 计算最终 Unicode 码点 */unsignedlongcp((uc-0xD800)10)(uc2-0xDC00)0x10000;/* 编码为 UTF-8 */...}}}/* 将码点编码为 UTF-8 字节序列 */...}break;Unicode 转义是parse_string中最复杂的部分涉及解析 4 位十六进制parse_hex4读取\uXXXX中的 4 个十六进制字符。代理对处理如果码点在0xD800~0xDBFF高代理区且后面紧跟\u则继续读取低代理区的 4 位十六进制组合成完整的 Unicode 码点范围0x10000~0x10FFFF。UTF-8 编码将 Unicode 码点转换为 1~4 字节的 UTF-8 序列。4.6 收尾写入 valuestring*output\0;item-valuestring(char*)output;*eppointer1;returntrue;第二遍扫描结束后在输出末尾写入\0将output赋值给item-valuestring并更新ep指向结束引号之后的位置返回成功。5. 关键细节与注意事项5.1 内存分配策略parse_string采用两遍扫描策略第一遍只统计长度不分配内存。第二遍才分配内存并填充。这样做的目的是精确分配内存避免过度分配或二次扩容。对于没有转义的字符串直接用memcpy一次复制性能更高。5.2 错误处理函数在以下情况返回false输入为空或开头不是引号。字符串未闭合缺少结束引号。转义序列不完整\后紧跟\0。未知的转义字符。内存分配失败。每次失败前都会释放已分配的内存避免内存泄漏。5.3 与 parse_value 的协作parse_string通常由parse_value调用。当parse_value遇到时会调用parse_string来解析字符串值case\:returnparse_string(item,input,ep);解析成功后item-type会被设置为cJSON_Stringitem-valuestring指向解析出的字符串。6. 完整源码精简注释版staticcJSON_boolparse_string(cJSON*item,constunsignedchar*constinput,constunsignedchar**ep){constunsignedchar*pointerinput1;size_tlength0;if(inputNULL||*input!\){returnfalse;}/* 第一遍计算长度 */while(*pointer!\*pointer!\0){if(*pointer\\){pointer;if(*pointer\0){returnfalse;}pointer;}else{pointer;}length;}if(*pointer!\){returnfalse;}if(pointerinput1){/* 空字符串 */item-valuestring(char*)cJSON_malloc(1);if(item-valuestringNULL){returnfalse;}item-valuestring[0]\0;*eppointer1;returntrue;}if(length(size_t)(pointer-input)-1){/* 无转义直接复制 */item-valuestring(char*)cJSON_malloc(length1);if(item-valuestringNULL){returnfalse;}memcpy(item-valuestring,input1,length);item-valuestring[length]\0;*eppointer1;returntrue;}/* 第二遍处理转义 */pointerinput1;unsignedchar*output(unsignedchar*)cJSON_malloc(length1);if(outputNULL){returnfalse;}while(*pointer!\*pointer!\0){if(*pointer!\\){*output*pointer;}else{pointer;switch(*pointer){caseb:*output\b;break;casef:*output\f;break;casen:*output\n;break;caser:*output\r;break;caset:*output\t;break;case\:*output\;break;case\\:*output\\;break;case/:*output/;break;caseu:/* Unicode 处理省略细节 */break;default:cJSON_free(output);returnfalse;}pointer;}}*output\0;item-valuestring(char*)output;*eppointer1;returntrue;}7. 总结parse_string是 cJSON 解析器中处理字符串的核心函数其设计体现了几个重要思想两遍扫描先统计长度再分配内存兼顾效率与精确性。无转义快路径对不含转义的字符串使用memcpy批量复制避免逐字符开销。完整的转义支持覆盖 JSON 规范定义的所有标准转义并正确处理 Unicode 代理对。严谨的错误处理每个失败路径都释放内存避免泄漏。理解parse_string的实现不仅能帮助你深入掌握 cJSON 的工作原理也能为阅读其他 JSON 解析库如 yyjson、jansson的字符串处理逻辑打下良好基础。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

为什么你需要双时间知识图谱?Utopia 核心设计理念完整解读 2026/10/1 21:31:01

为什么你需要双时间知识图谱?Utopia 核心设计理念完整解读

为什么你需要双时间知识图谱?Utopia 核心设计理念完整解读 【免费下载链接】utopia 首个开源企业世界模型 项目地址: https://gitcode.com/deeplethe/utopia Utopia 是由 DeepLethe 打造的首个开源企业世界模型,它的底座是一套双时间知识图谱&…

阅读更多 →
Shulex VOC AI 功能解析及Shulex渠道邀请码(shulex优惠折扣码) 2026/10/1 21:31:01

Shulex VOC AI 功能解析及Shulex渠道邀请码(shulex优惠折扣码)

Shulex VOC AI 功能解析及Shulex渠道邀请码(shulex优惠折扣码)做跨境电商时,产品评论不仅是消费者对商品的评价,也是卖家了解市场需求的重要信息来源。一款产品为什么有人喜欢?消费者购买后最容易遇到什么问题&#xf…

阅读更多 →
JavaWeb人事系统拆解:Servlet/JSP+JDBC架构部署与避坑指南 2026/10/1 21:31:00

JavaWeb人事系统拆解:Servlet/JSP+JDBC架构部署与避坑指南

简介:一份基于JavaWeb的企业人事管理系统毕业设计源码包,面向计算机相关专业学生与Java初学者,用来学习Servlet/JSP、JDBC、MVC分层以及Tomcat部署等Web开发全流程。系统功能覆盖用户管理、员工信息、部门职位、考勤、薪酬福利、绩效、培训与…

阅读更多 →
如何打造一个像童锦程.skill的人物Skill:女娲方法论开发者实战指南 2026/10/1 21:31:00

如何打造一个像童锦程.skill的人物Skill:女娲方法论开发者实战指南

如何打造一个像童锦程.skill的人物Skill:女娲方法论开发者实战指南 【免费下载链接】tong-jincheng-skill 童锦程视角 Skill — 用深情祖师爷的思维框架分析人际关系 项目地址: https://gitcode.com/gh_mirrors/to/tong-jincheng-skill 本文以开源项目童锦程…

阅读更多 →
2026国内GMP洁净室浮游菌采样器测评与解析 2026/10/1 21:30:41

2026国内GMP洁净室浮游菌采样器测评与解析

目录一、洁净室微生物监测的监管背景二、默克MAS-100采样器系列梳理三、时间因子:采样流速与环境补偿四、两款采样器的规格拆解对比五、采样效率与数据追溯能力差异六、使用场景与洁净级别适配七、领域认证与GMP合规体系八、常见问题FAQ一、洁净室微生物监测的监管背…

阅读更多 →
循环引用把我坑惨了,Python的垃圾回收不是万能的 2026/10/1 21:30:41

循环引用把我坑惨了,Python的垃圾回收不是万能的

"服务跑了一个月突然OOM,重启后内存又慢慢涨上去——直到我在火焰图上看到两个相亲相爱的类互相搂着脖子不撒手。" 这是去年我们团队处理的一个真实生产问题,一个本该被垃圾回收的对象,因为循环引用成了内存泄漏的钉子户。 当优雅的…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉