cJSON源码解析之add_item_to_object函数

文章目录

  • 前言
  • add_item_to_object函数是干什么的
  • add_item_to_object代码解析
    • 函数实现
    • 函数原理解析
      • 开头的代码
      • constant_key参数的作用
      • 最后的if判断
    • add_item_to_array函数
  • 总结


前言

在我们的日常编程中,JSON已经成为了一种非常常见的数据交换格式。在C语言中,我们通常使用cJSON库来处理JSON数据。cJSON库提供了一系列的函数来创建、解析和操作JSON数据。其中,add_item_to_object函数是一个关键的函数,它允许我们将一个新的项目添加到一个已存在的JSON对象中。在这篇文章中,我们将深入探讨add_item_to_object函数的内部实现。


add_item_to_object函数是干什么的

这个函数用于把一个item添加到一个对象里面
他是cJSON_AddItemToObjectcJSON_AddItemToObjectCS函数的实现
在这里插入图片描述

add_item_to_object代码解析

函数实现

static cJSON_bool add_item_to_object(cJSON * const object, const char * const string, cJSON * const item, const internal_hooks * const hooks, const cJSON_bool constant_key)
{char *new_key = NULL;int new_type = cJSON_Invalid;if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item)){return false;}if (constant_key){new_key = (char*)cast_away_const(string);new_type = item->type | cJSON_StringIsConst;}else{new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);if (new_key == NULL){return false;}new_type = item->type & ~cJSON_StringIsConst;}if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)){hooks->deallocate(item->string);}item->string = new_key;item->type = new_type;return add_item_to_array(object, item);
}

函数原理解析

开头的代码

首先他声明了两个变量,用于存储key值和该键值对的类型的

char *new_key = NULL;
int new_type = cJSON_Invalid;

紧接着,他去判断参数的合法性,为了内存的异常安全:‘

if ((object == NULL) || (string == NULL) || (item == NULL) || (object == item))
{return false;
}

constant_key参数的作用

在cJSON库中,constant_key参数是一个布尔值,它决定了键(key)是进行深拷贝还是浅拷贝。

如果constant_keytrue,那么在添加新项目到JSON对象时,键(key)将会进行浅拷贝,也就是直接复制指针。这意味着,如果原始的键字符串在以后被修改或释放,那么存储在JSON对象中的键也会受到影响。

如果constant_keyfalse,那么键(key)将会进行深拷贝,也就是复制整个字符串的内容到新的内存位置。这样,即使原始的键字符串在以后被修改或释放,也不会影响到存储在JSON对象中的键。

可以看到他的浅拷贝和深拷贝是完全不同的:
在这里插入图片描述

if (constant_key)
{new_key = (char*)cast_away_const(string);new_type = item->type | cJSON_StringIsConst;
}
else
{new_key = (char*)cJSON_strdup((const unsigned char*)string, hooks);if (new_key == NULL){return false;}new_type = item->type & ~cJSON_StringIsConst;
}

在浅拷贝,直接把参数的key复制到new_key里面,然后把new_type赋值成对应的类型
那么他为何要| cJSON_StringIsConst
这行代码中的|操作符是C语言中的位运算符,表示按位或操作。cJSON_StringIsConst是一个常量,它的值通常为0x200,在二进制中表示为10 0000 0000

当我们执行item->type | cJSON_StringIsConst时,实际上是将item->type的值和cJSON_StringIsConst的值进行按位或操作。这样做的目的是为了将item->type的第10位设置为1,而不改变其他位的值。

这里cJSON_StringIsConst的作用是标记字符串是否为常量。如果一个字符串被标记为常量,那么在cJSON对象被删除时,这个字符串就不会被释放。这对于那些指向静态或全局变量的字符串非常有用,因为这些字符串不能被释放。

所以,new_type = item->type | cJSON_StringIsConst;这行代码的作用就是将item->type的值更新为新的类型,同时保留了原来的类型信息,并标记字符串为常量。

在深拷贝中,使用了cJSON_strdup函数复制字符串,我们上篇文章已经介绍过
new_type = item->type & ~cJSON_StringIsConst;类比上面,这段代码也就是把这个字符串标记为不是常量,在删除的时候可以直接删除

最后的if判断

这段代码的目的是在添加新的键值对到JSON对象时,安全地处理旧的键字符串。

if (!(item->type & cJSON_StringIsConst) && (item->string != NULL))
{hooks->deallocate(item->string);
}

!(item->type & cJSON_StringIsConst)这段的含义如下:
这部分是检查item->type是否被标记为cJSON_StringIsConst。如果被标记为cJSON_StringIsConst,那么这个字符串就是一个常量字符串,我们不能释放它。所以,我们使用!操作符来检查item->type是否没有被标记为cJSON_StringIsConst

(item->string != NULL):这部分是检查item->string是否为NULL。如果item->string为NULL,那么我们就没有必要(也不能)释放它。

最后就把参数item复制上我们的状态就行了:

item->string = new_key;
item->type = new_type;

我们会发现,这个函数仅仅是把键和type安装到参数type上面,但是还没有进行item安装到object上面,所以这里又出现一个函数,他专门用于链表的操作的add_item_to_array

add_item_to_array函数

add_item_to_array函数代码如下:

static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{cJSON *child = NULL;if ((item == NULL) || (array == NULL) || (array == item)){return false;}child = array->child;/** To find the last item in array quickly, we use prev in array*/if (child == NULL){/* list is empty, start new one */array->child = item;item->prev = item;item->next = NULL;}else{/* append to the end */if (child->prev){suffix_object(child->prev, item);array->child->prev = item;}}return true;
}

他的主要代码如下:

if (child == NULL)
{/* list is empty, start new one */array->child = item;item->prev = item;item->next = NULL;
}
else
{/* append to the end */if (child->prev){suffix_object(child->prev, item);array->child->prev = item;}
}

他的图例:

  1. 如果链表为空 (child == NULL),那么新的item就会成为链表的第一个(也是唯一的)元素。这个情况可以用下面的字符画来表示:
array|vitem  --> NULL^|item

在这个图中,array->child指向itemitem->prev指向item自身,item->next指向NULL

  1. 如果链表不为空,那么新的item就会被添加到链表的末尾。这个情况可以用下面的字符画来表示:
array|vchild1 <--> child2 <--> ... <--> childN <--> item --> NULL^                                          ^|                                          |child1                                    item

在这个图中,array->child指向链表的第一个元素child1childN->next指向新的itemitem->prev指向childNitem->next指向NULL

这样就成功的把我们的item连接到object里面了


总结

通过深入研究add_item_to_object函数的源码,我们可以更好地理解cJSON库是如何处理JSON对象的。这个函数的实现虽然简单,但却非常关键,它使得我们可以方便地向JSON对象中添加新的项目。希望这篇文章能帮助你更好地理解cJSON库的内部工作原理,以及如何在你自己的项目中使用它。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/863819.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

UI Toolkit系统学习

UI Toolkit 此文章用于学习UnityUI系统&#xff0c;手头的项目做完会来完善 官方文档 Unity上方菜单栏点击Window->UI Toolkit->Samples可以看UI Toolkit中的很多样例 使用 UI Toolkit 和 UI Builder 制作物品编辑器 在文件夹中右键->Create->UI Toolkit->Edi…

leetCode-hot100-动态规划专题

动态规划 动态规划定义动态规划的核心思想动态规划的基本特征动态规划的基本思路例题322.零钱兑换53.最大子数组和72.编辑距离139.单词拆分62.不同路径63.不同路径Ⅱ64.最小路径和70.爬楼梯121.买卖股票的最佳时机152.乘积最大子数组 动态规划定义 动态规划&#xff08;Dynami…

【训练篇】MLU370-M8 完成 qwen1.5-7b-chat-lora训练及推理

文章目录 前言一、平台环境配置二、环境 or 模型准备1.模型下载2.环境准备2.1 modelscope2.2 transformers2.3 accelerate2.4 deepspeed2.5 peft2.6 环境代码修改 3训练代码准备4 代码修改 三&#xff0c;训练后推理验证四.推理效果展示1.微调前2.微调后 前言 本期我们采用魔塔…

distance delayed sound

distance delayed sound 在本章中&#xff0c;我们将讨论在游戏音频中使用距离延迟的重要性。我们将首先通过一个常见的例子——闪电和雷鸣&#xff0c;来展示这种重要性并解释距离延迟音频的基础知识。我们将讨论计算速度、距离和时间的数学和方程式&#xff0c;以确定距离延迟…

数据倾斜优化:Hive性能提升的核心

文章目录 1. 定义2. 数据倾斜2.1 Map2.2 Join2.3 Reduce 3. 写在最后 1. 定义 数据倾斜&#xff0c;也称为Data Skew&#xff0c;是在分布式计算环境中&#xff0c;由于数据分布不均匀导致某些任务处理的数据量远大于其他任务&#xff0c;从而形成性能瓶颈的现象。这种情况在H…

PotPlayer安装及高分辨率设置

第1步&#xff1a; 下载安装PotPlayer软件 PotPlayer链接&#xff1a;https://pan.baidu.com/s/1hW168dJrLBonUnpLI6F3qQ 提取码&#xff1a;z8xd 第2步&#xff1a; 下载插件&#xff0c;选择系统对应的位数进行运行&#xff0c;该文件不能删除&#xff0c;删除后将失效。 …

【强化学习的数学原理】课程笔记--2(贝尔曼最优公式,值迭代与策略迭代)

目录 贝尔曼最优公式最优 Policy求解贝尔曼最优公式求解最大 State Value v ∗ v^* v∗根据 v ∗ v^* v∗ 求解贪婪形式的最佳 Policy π ∗ \pi^* π∗一些证明过程 一些影响 π ∗ \pi^* π∗ 的因素如何让 π ∗ \pi^* π∗ 不 “绕弯路” γ \gamma γ 的影响reward 的…

2024/6/30周报

文章目录 摘要ABSTRACT文献阅读题目问题本文贡献方法LSTMTCN模型总体架构 实验实验结果 深度学习TCN-LSTM代码运行结果 总结 摘要 本周阅读了一篇关于TCN和LSTM进行光伏功率预测的文章&#xff0c;本文提出了一种利用LSTM-TCN预测光伏功率的新模型。它由长短期记忆和时间卷积网…

ThreadPoolExecutor基于ctl变量的声明周期管理

个人博客 ThreadPoolExecutor基于ctl变量的声明周期管理 | iwts’s blog 总集 想要完整了解下ThreadPoolExecutor&#xff1f;可以参考&#xff1a; 基于源码详解ThreadPoolExecutor实现原理 | iwts’s blog ctl字段的应用 线程池内部使用一个变量ctl维护两个值&#xff…

树莓派开发之文件传输

文章目录 一、简介使用U盘传输文件使用SD卡传输文件使用Xftp 7传输文件 二、 总结 一、简介 在树莓派开发中经常会用到文件传输&#xff0c;下面介绍几种树莓派文件传输的几种方法。 使用U盘传输文件 &#xff08;1&#xff09;复制所需传输文件到U盘 &#xff08;2&#…

C++:typeid4种cast转换

typeid typeid typeid是C标准库中提供的一种运算符&#xff0c;它用于获取类型的信息。它主要用于类型检查和动态类型识别。当你对一个变量或对象使用typeid运算符时&#xff0c;它会返回一个指向std::type_info类型的指针&#xff0c;这个信息包含了关于该类型名称、大小、基…

Pikachu靶场--Sql Inject

参考借鉴 pikachu靶场练习&#xff08;详细&#xff0c;完整&#xff0c;适合新手阅读&#xff09;-CSDN博客 数字型注入(post) 这种类型的SQL注入利用在用户输入处插入数值&#xff0c;而不是字符串。攻击者试图通过输入数字来修改SQL查询的逻辑&#xff0c;以执行恶意操作。…

Unity Shader 极坐标

Unity Shader 极坐标 前言项目简单极坐标极坐标变体之方形极坐标变体之圆形拉花 鸣谢 前言 极坐标记录 项目 简单极坐标 极坐标变体之方形 极坐标变体之圆形 拉花 鸣谢 【菲兹杂货铺】【Unity Shader教程】极坐标实现以及极坐标的两种变体

【87 backtrader期权策略】基于50ETF期权的covered-call-strategy

前段时间有读者希望能够实现一个期权策略的模板,这段时间通过akshare下载了期权的数据,并进行了清洗,写了一个最简单的期权策略,供大家参考。 策略逻辑: 这是151 trading strategies中的一个期权策略。 买入50ETF基金,手续费按照万分之二计算,一直持有卖出一个最远期的…

【实施】系统实施方案(软件方案Word)

软件实施方案 二、 项目介绍 三、 项目实施 四、 项目实施计划 五、 人员培训 六、 项目验收 七、 售后服务 八、 项目保障措施 软件开发全套资料获取&#xff1a;私信或者进主页获取。 软件产品&#xff0c;特别是行业解决方案软件产品不同于一般的商品&#xff0c;用户购买软…

13_旷视轻量化网络--ShuffleNet V2

回顾一下ShuffleNetV1:08_旷视轻量化网络--ShuffleNet V1-CSDN博客 1.1 简介 ShuffleNet V2是在2018年由旷视科技的研究团队提出的一种深度学习模型&#xff0c;主要用于图像分类和目标检测等计算机视觉任务。它是ShuffleNet V1的后续版本&#xff0c;重点在于提供更高效的模…

antd Select前端加模糊搜索

背景&#xff1a;前端的小伙伴经常在开发antd Select的时候后端不提供搜索模糊搜索接口&#xff0c;而是全量返回数据&#xff0c;这个时候就需要我们前端自己来写一个模糊搜索了。 效果 代码截图 代码 <SelectshowSearchmode"multiple"options{studioList}filte…

运维锅总详解Prometheus

本文尝试从Prometheus简介、架构、各重要组件详解、relable_configs最佳实践、性能能优化及常见高可用解决方案等方面对Prometheus进行详细阐述。希望对您有所帮助&#xff01; 一、Prometheus简介 Prometheus 是一个开源的系统监控和报警工具&#xff0c;最初由 SoundCloud …

基于模糊神经网络的时间序列预测(以hopkinsirandeath数据集为例,MATLAB)

模糊神经网络从提出发展到今天,主要有三种形式&#xff1a;算术神经网络、逻辑模糊神经网络和混合模糊神经网络。算术神经网络是最基本的&#xff0c;它主要是对输入量进行模糊化&#xff0c;且网络结构中的权重也是模糊权重&#xff1b;逻辑模糊神经网络的主要特点是模糊权值可…

Python技术笔记汇总(含语法、工具库、数科、爬虫等)

对Python学习方法及入门、语法、数据处理、数据可视化、空间地理信息、爬虫、自动化办公和数据科学的相关内容可以归纳如下&#xff1a; 一、Python学习方法 分解自己的学习目标&#xff1a;可以将学习目标分基础知识&#xff0c;进阶知识&#xff0c;高级应用&#xff0c;实…