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
  |
  v
 item  --> NULL
  ^
  |
 item

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

  1. 如果链表不为空,那么新的item就会被添加到链表的末尾。这个情况可以用下面的字符画来表示:
array
  |
  v
 child1 <--> 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库的内部工作原理,以及如何在你自己的项目中使用它。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[深度学习] 卷积神经网络CNN

卷积神经网络&#xff08;Convolutional Neural Network, CNN&#xff09;是一种专门用于处理数据具有类似网格结构的神经网络&#xff0c;最常用于图像数据处理。 一、CNN的详细过程&#xff1a; 1. 输入层 输入层接收原始数据&#xff0c;例如一张图像&#xff0c;它可以被…

Qt 实战(6)事件 | 6.1、事件机制

文章目录 一、事件1、基本概念2、事件描述3、事件循环4、事件分发4.1、QApplication::notify()4.2、QObject::event() 5、事件传递6、事件处理器 前言&#xff1a; Qt 框架中的事件机制&#xff08;Event Mechanism&#xff09;是一种核心功能&#xff0c;它允许应用程序以事件…

【Launcher3】解决谷歌桌面的小部件重启后消失问题

1-问题摘要 这次主要解决困扰了我很久的时钟消失问题&#xff0c;大概是去年10月刚开始做EDLA项目的时候&#xff0c;需要定制谷歌桌面&#xff0c;桌面布局大概要改成这样&#xff1a; 时间显示在谷歌搜索框的上方,而安卓原生桌面大概是这样子的 我们开发一开始是使用小部件…

微服务+云原生:打造高效、灵活的分布式系统

&#x1f407;明明跟你说过&#xff1a;个人主页 &#x1f3c5;个人专栏&#xff1a;《未来已来&#xff1a;云原生之旅》&#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目录 一、引言 1、云原生概述 2、微服务概述 二、微服务架构基础 1、…

二、反应式集成-spring

一、Spring WebFlux what 1、简介 - Spring WebFlux 包含一个用于执行 HTTP 请求的客户端。 有一个 基于 Reactor 的功能性、流畅的 API&#xff0c;请参阅 Reactive Libraries&#xff0c; 它支持异步逻辑的声明性组合&#xff0c;而无需处理 线程或并发。它是完全无阻塞的…

Talking Web

1. curl 1.1 http curl http://127.0.0.1:80 向目标主机端口发送http请求 1.2 httphead curl -H “Host: 18ed3df584cd48328b5839443aa7b42b” http://127.0.0.1:80 1.3 httppath curl http://127.0.0.1:80/853c64cd218f80d0a59665666fb2ab80 1.4 URL编码路径 &#xff0…

Python学习笔记21:进阶篇(十)常见标准库使用之math模块,random模块和statistics模块

前言 本文是根据python官方教程中标准库模块的介绍&#xff0c;自己查询资料并整理&#xff0c;编写代码示例做出的学习笔记。 根据模块知识&#xff0c;一次讲解单个或者多个模块的内容。 教程链接&#xff1a;https://docs.python.org/zh-cn/3/tutorial/index.html 数学 P…

微软结束将数据中心置于海底的实验

2016 年&#xff0c;微软 宣布了一项名为"纳蒂克项目"&#xff08;Project Natick&#xff09;的实验。基本而言&#xff0c;该项目旨在了解数据中心能否在海洋水下安装和运行。经过多次较小规模的测试运行后&#xff0c;该公司于 2018 年春季在苏格兰海岸外 117 英尺…

从0开始C++(八):多态的实现

相关文章&#xff1a; 从0开始C&#xff08;一&#xff09;&#xff1a;从C到C 从0开始C&#xff08;二&#xff09;&#xff1a;类、对象、封装 从0开始C&#xff08;三&#xff09;&#xff1a;构造函数与析构函数详解 从0开始C&#xff08;四&#xff09;&#xff1a;作…

React+TS前台项目实战(十九)-- 全局Input组件封装:加载状态和清除功能的实现

文章目录 前言Input组件1. 功能分析2. 代码详细注释3. 使用方式4. 效果展示 总结 前言 今天我们来封装一个input输入框组件&#xff0c;并提供一些常用的功能&#xff0c;你可以选择不同的 尺寸、添加前缀、显示加载状态、触发回调函数、自定义样式 等等。这些功能在这个项目中…

vite+vue3+ts项目搭建流程 (pnpm, eslint, prettier, stylint, husky,commitlint )

vitevue3ts项目搭建 项目搭建项目目录结构 项目配置自动打开项目eslint①vue3环境代码校验插件②修改.eslintrc.cjs配置文件③.eslintignore忽略文件④运行脚本 prettier①安装依赖包②.prettierrc添加规则③.prettierignore忽略文件④运行脚本 stylint①.stylelintrc.cjs配置文…

【云原生】Kubernetes网络知识

Kubernetes网络管理 文章目录 Kubernetes网络管理一、案例概述二、案例前置知识点2.1、Kubernetes网络模型2.2、Docker网络基础2.3、Kubernetes网络通信2.3.1、Pod内容器与内容之间的通信2.3.2、Pod与Pod之间的通信 2.4、Flannel网络插件2.5、Calico网络插件2.5.1、Calico网络模…

免费下载电子书的网站

在如今的数字化时代&#xff0c;电子书已成为许多人书籍阅读的首选。下面小编就和大家分享一些提供免费查找下载电子书服务的网站&#xff0c;这些网站不仅资源丰富&#xff0c;而且操作简便。 免费下载电子书的网站&#xff1a;https://www.bgrdh.com/favorites/1355.html 1…

数据可视化期末考试(编程)

1.KNN 1.新增数据的分类 import pandas as pd # 您的原始数据字典 data { 电影名称: [电影1, 电影2, 电影3, 电影4, 电影5], 打斗镜头: [10, 5, 108, 115, 20], 接吻镜头: [110, 89, 5, 8, 200], 电影类型: [爱情片, 爱情片, 动作片, 动作片, 爱情片] } …

昇思25天学习打卡营第8天 | 模型的保存与加载

内容介绍&#xff1a;在训练网络模型的过程中&#xff0c;实际上我们希望保存中间和最后的结果&#xff0c;用于微调&#xff08;fine-tune&#xff09;和后续的模型推理与部署&#xff0c;本章节我们将介绍如何保存与加载模型。 具体内容&#xff1a; 1. 导包 import numpy…

1.1 MySQL用户管理

1.1.1 用户的定义 用户名主机域 mysql> select user,host,password from mysql.user; --------------------------------------------------------------- | user | host | password | -----------------------------------------…

el-form重置后input无法输入问题

新增用户遇到的问题&#xff1a; 如果你没有为 formData 设置默认值&#xff0c;而只是将其初始化为空对象 {}&#xff0c;则在打开dialog时&#xff0c;正常输入&#xff0c; formdata会变成如下 但是&#xff0c;打开后&#xff0c;直接使用 resetFields 或直接清空表单&…

LLDB 详解

LLDB 详解 LLDB 详解编译器集成优势LLDB 的主要功能命令格式原始&#xff08;raw&#xff09;命令选项终止符: -- LLDB 中的变量唯一匹配原则helpexpressionprint、call、po控制流程&#xff1a;continue、next、step、finishregister read / writethread backtracethread retu…

基于weixin小程序新生报到系统的设计

管理员账户功能包括&#xff1a;系统首页&#xff0c;个人中心&#xff0c;学生管理&#xff0c;班级信息管理&#xff0c;师资力量管理&#xff0c;宿舍信息管理&#xff0c;宿舍安排管理&#xff0c;签到信息管理&#xff0c;论坛管理 小程序功能包括&#xff1a;系统首页&am…

考研数学一有多难?130+背后的残酷真相

考研数学一很难 大家平时在网上上看到很多人说自己考了130&#xff0c;其实这些人只占参加考研数学人数的极少部分&#xff0c;有个数据可以展示出来考研数学到底有多难&#xff1a; 在几百万考研大军中&#xff0c;能考到120分以上的考生只有2%。绝大多数人的分数集中在30到…