cJSON代码解读

1、背景

cJSON用了很久,但是对它一直不太了解。这次向添加对long long类型的支持,一直出问题。因为有以前添加两位小数float的经历,我觉得会很轻松,没想到翻车了。于是有了这边文档,阅读了部分博主对cJSON的解析,给出自己的体悟。

1.1 参考文档

【万字详解】cJSON解析-CSDN博客

2 从使用者角度分析

2.1 数据结构上分析

cJSON在使用上来说有两种:

1、将json字符串输入得到key-value;

2、将key-value输入得到一个json字符串;

两者的桥梁就是cJSON提供结构体cJSON,由该结构体通过链表形成一个树来表征一个JSON。

一个cJSON结构体是对JSON数据的抽象。

  /* The cJSON structure: */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 number, if type==cJSON_Int64 */long long valueint64;/* 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是子节点;

string 是该节点的key,而value 可以根据type类型来决定,是valuestring、valueint、valuedouble、valueint64。

 接下去就是从使用角度分析,分别是组包JSON和解析JSON字符串两个角度出发。

2.2组包JSON

涉及到的函数如下所述,由创建cJSON、添加子节点、转成字符串、删除cJSON等过程。

  /*创建节点*/CJSON_PUBLIC(cJSON *)cJSON_CreateArray(void);CJSON_PUBLIC(cJSON *)cJSON_CreateObject(void);/*添加子节点*/CJSON_PUBLIC(cJSON *)cJSON_AddNumberToObject(cJSON *const object, const char *const name, const double number);CJSON_PUBLIC(cJSON *)cJSON_AddDoubleToObject(cJSON *const object, const char *const name, const double number);CJSON_PUBLIC(cJSON *)cJSON_AddInt64ToObject(cJSON *const object, const char *const name, const long long number);CJSON_PUBLIC(cJSON *)cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string);/*添加子节点2*/  CJSON_PUBLIC(void)cJSON_AddItemToArray(cJSON *array, cJSON *item);CJSON_PUBLIC(void)cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item);/*cJSON对象转字符串*/   /* Render a cJSON entity to text for transfer/storage. */CJSON_PUBLIC(char *)cJSON_Print(const cJSON *item);CJSON_PUBLIC(void)cJSON_Minify(char *json);/*删除cJSON对象*/   /* Delete a cJSON entity and all subentities. */CJSON_PUBLIC(void)cJSON_Delete(cJSON *c);

每个过程看一两个函数实现

2.2.1 创建节点指定类型的节点

/* Internal constructor. */
static cJSON *cJSON_New_Item(const internal_hooks *const hooks)
{cJSON *node = (cJSON *)hooks->allocate(sizeof(cJSON));if (node){memset(node, '\0', sizeof(cJSON));}return node;
}
CJSON_PUBLIC(cJSON *)
cJSON_CreateObject(void)
{cJSON *item = cJSON_New_Item(&global_hooks);if (item){item->type = cJSON_Object;}return item;
}

 申请一个新的节点,成功则将类型设置成创建的类型,返回该节点。

这里涉及到一个类型的说法

/* cJSON Types: */
#define cJSON_Invalid (0)            /*无实际意义值,初始化节点时状态*/
#define cJSON_False (1 << 0)        /*布尔类型false*/
#define cJSON_True (1 << 1)        /*布尔类型true*/
#define cJSON_NULL (1 << 2)        /*空类型NULL*/
#define cJSON_Number (1 << 3)        /*数值类型*/
#define cJSON_String (1 << 4)        /*字符串类型*/
#define cJSON_Array (1 << 5)        /*列表类型, child存储值*/
#define cJSON_Object (1 << 6)        /*对象类型, child存储值*/
#define cJSON_Raw (1 << 7) /* raw json 表示valuestring中以\0结尾字符数据的任何类型*/
#define cJSON_Double (1 << 8)         /*浮点类型*/   
#define cJSON_Int64 (1 << 9)        /*long long int类型*/ #define cJSON_Valid_Flags (0x03FF)
/*两个标志*/
#define cJSON_IsReference (512)     /*标记child指向或valuestring不属于该节点,无需释放*/
#define cJSON_StringIsConst (1 << 10)    /*string成员是一个常量,无需释放*/

如上述代码所述,用位来标记是什么类型的。

另外还有两个标志,分别

(1)表示该节点是个引用,其中的child和valuestring不属于该节点,释放时注意;

(2)表示该节点的string成员指向的是个常量,无需释放。

 2.2.2 删除节点

/* Delete a cJSON structure. */
CJSON_PUBLIC(void)
cJSON_Delete(cJSON *item)
{cJSON *next = NULL;while (item != NULL)    /*循环直至链表释放完*/{next = item->next;    /*链表下一个兄弟节点*/printf("item type 0x%x\n", item->type);/*节点不带引用标志,且有子节点,则释放子节点*/if (!(item->type & cJSON_IsReference) && (item->child != NULL)){cJSON_Delete(item->child);}/*节点不带引用标志,且有valuestring,则释放valuestring*/if (!(item->type & cJSON_IsReference) && (item->valuestring != NULL)){global_hooks.deallocate(item->valuestring);}/*节点不是常量标志,则释放string*/if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)){global_hooks.deallocate(item->string);}/*释放节点本身*/global_hooks.deallocate(item);item = next;    /*item=下一个兄弟节点*/}
}

 具体看代码注释

和创建节点中标志位一一对应。释放节点下子节点和一切动态分配的资源。

 2.2.3添加子节点1

/*
* @fn add_item_to_object
* @param object The object to add to.
* @param string The string in key.
* @param item The item to add.
* @param hooks The hooks to use.
* @param constant_key Whether the key is a constant or not.
* @return true on success, false on failure.
*/
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)
{if ((object == NULL) || (string == NULL) || (item == NULL)){return false;}if (!(item->type & cJSON_StringIsConst) && (item->string != NULL)){hooks->deallocate(item->string);}if (constant_key){item->string = (char *)cast_away_const(string);item->type |= cJSON_StringIsConst;}else{char *key = (char *)cJSON_strdup((const unsigned char *)string, hooks);if (key == NULL){return false;}item->string = key;item->type &= ~cJSON_StringIsConst;}return add_item_to_array(object, item);
}static cJSON_bool add_item_to_array(cJSON *array, cJSON *item)
{cJSON *child = NULL;if ((item == NULL) || (array == NULL)){return false;}child = array->child;if (child == NULL){/* list is empty, start new one */array->child = item;}else{/* append to the end */while (child->next){child = child->next;}suffix_object(child, item);}return true;
}/*
* @fn cJSON_AddStringToObject
* @param object The object to add to.
* @param name The name of the item to add.
* @param string The string to add.
* @return The new item, or NULL on failure.
*/
CJSON_PUBLIC(cJSON *)
cJSON_AddStringToObject(cJSON *const object, const char *const name, const char *const string)
{cJSON *string_item = cJSON_CreateString(string);if (add_item_to_object(object, name, string_item, &global_hooks, false)){return string_item;}cJSON_Delete(string_item);return NULL;
}

cJSON_AddStringToObject函数向object节点中添加key是name, value是string的子节点,先将value复制给了valuestring成员;

在add_item_to_object根据constant_key的值,给key赋了值,对type成员设置关于cJSON_StringIsConst标志的值;

add_item_to_array将子节点添加在父节点的child成员指向的链表下

2.2.4 添加子节点2

CJSON_PUBLIC(void)
cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item)
{add_item_to_object(object, string, item, &global_hooks, false);
}

也调用了add_item_to_object,不再叙述

2.2.5 cJSON结构体转字符串

static unsigned char *print(const cJSON *const item, cJSON_bool format, const internal_hooks *const hooks)
{static const size_t default_buffer_size = 256;printbuffer buffer[1];unsigned char *printed = NULL;memset(buffer, 0, sizeof(buffer));/* create buffer */buffer->buffer = (unsigned char *)hooks->allocate(default_buffer_size);buffer->length = default_buffer_size;buffer->format = format;buffer->hooks = *hooks;if (buffer->buffer == NULL){goto fail;}/* print the value */if (!print_value(item, buffer)){goto fail;}update_offset(buffer);/* check if reallocate is available */if (hooks->reallocate != NULL){printed = (unsigned char *)hooks->reallocate(buffer->buffer, buffer->offset + 1);buffer->buffer = NULL;if (printed == NULL){goto fail;}}else /* otherwise copy the JSON over to a new buffer */{printed = (unsigned char *)hooks->allocate(buffer->offset + 1);if (printed == NULL){goto fail;}memcpy(printed, buffer->buffer, cjson_min(buffer->length, buffer->offset + 1));printed[buffer->offset] = '\0'; /* just to be sure *//* free the buffer */hooks->deallocate(buffer->buffer);}return printed;fail:if (buffer->buffer != NULL){hooks->deallocate(buffer->buffer);}if (printed != NULL){hooks->deallocate(printed);}return NULL;
}
/* Render a cJSON item/entity/structure to text. */
CJSON_PUBLIC(char *)
cJSON_Print(const cJSON *item)
{return (char *)print(item, true, &global_hooks);
}

 简单就是cJSON_Print

        ->print

                ->print_value

                ->realloc

                ->return printed;

核心看print_value


/* Render a value to text. */
static cJSON_bool print_value(const cJSON *const item, printbuffer *const output_buffer)
{unsigned char *output = NULL;/*检查输入和输出参数*/if ((item == NULL) || (output_buffer == NULL)){return false;}/*排除标志影响,直接看item是什么类型的*/switch ((item->type) & cJSON_Valid_Flags){case cJSON_NULL:output = ensure(output_buffer, 5);if (output == NULL){return false;}strcpy((char *)output, "null");return true;case cJSON_False:output = ensure(output_buffer, 6);if (output == NULL){return false;}strcpy((char *)output, "false");return true;case cJSON_True:output = ensure(output_buffer, 5);if (output == NULL){return false;}strcpy((char *)output, "true");return true;case cJSON_Number:return print_number(item, output_buffer);case cJSON_Double:return print_double(item, output_buffer);case cJSON_Int64:return print_int64(item, output_buffer);case cJSON_Raw:{size_t raw_length = 0;if (item->valuestring == NULL){if (!output_buffer->noalloc){output_buffer->hooks.deallocate(output_buffer->buffer);}return false;}raw_length = strlen(item->valuestring) + sizeof("");output = ensure(output_buffer, raw_length);if (output == NULL){return false;}memcpy(output, item->valuestring, raw_length);return true;}case cJSON_String:return print_string(item, output_buffer);case cJSON_Array:return print_array(item, output_buffer);case cJSON_Object:return print_object(item, output_buffer);default:return false;}
}

 根据cJSON对象所述类型进行字符串化,我们关注一个object、array、num这三种类型,string类型用脚趾都能想到。

2.2.5.1 print_object
/* Render an object to text. */
static cJSON_bool print_object(const cJSON *const item, printbuffer *const output_buffer)
{unsigned char *output_pointer = NULL;size_t length = 0;cJSON *current_item = item->child;if (output_buffer == NULL){return false;}/* Compose the output: */length = (size_t)(output_buffer->format ? 2 : 1); /* fmt: {\n */output_pointer = ensure(output_buffer, length + 1);if (output_pointer == NULL){return false;}/*花括号前部分*/*output_pointer++ = '{';output_buffer->depth++;if (output_buffer->format){*output_pointer++ = '\n';}output_buffer->offset += length;while (current_item){if (output_buffer->format){size_t i;output_pointer = ensure(output_buffer, output_buffer->depth);if (output_pointer == NULL){return false;}for (i = 0; i < output_buffer->depth; i++){*output_pointer++ = '\t';}output_buffer->offset += output_buffer->depth;}/*子节点的key*//* print key */if (!print_string_ptr((unsigned char *)current_item->string, output_buffer)){return false;}update_offset(output_buffer);length = (size_t)(output_buffer->format ? 2 : 1);output_pointer = ensure(output_buffer, length);if (output_pointer == NULL){return false;}/*key-value分隔符*/*output_pointer++ = ':';if (output_buffer->format){*output_pointer++ = '\t';}output_buffer->offset += length;/*子节点value,调用print_value*//* print value */if (!print_value(current_item, output_buffer)){return false;}update_offset(output_buffer);/* print comma if not last */length = (size_t)((output_buffer->format ? 1 : 0) + (current_item->next ? 1 : 0));output_pointer = ensure(output_buffer, length + 1);if (output_pointer == NULL){return false;}if (current_item->next){/*如果子节点有下一个兄弟节点,加逗号*//* print value */*output_pointer++ = ',';}if (output_buffer->format){*output_pointer++ = '\n';}*output_pointer = '\0';output_buffer->offset += length;current_item = current_item->next;}output_pointer = ensure(output_buffer, output_buffer->format ? (output_buffer->depth + 1) : 2);if (output_pointer == NULL){return false;}if (output_buffer->format){size_t i;for (i = 0; i < (output_buffer->depth - 1); i++){*output_pointer++ = '\t';}}/*花括号后部分*/*output_pointer++ = '}';*output_pointer = '\0';output_buffer->depth--;return true;
}

 object类型的cJSON对象输出字符串类似下图,具体格式细节还是根据format来控制

{
"child_key":"child_value"
}

format为true时,配合\t和深度来缩进完成格式化。

2.2.5.2 print_array
/* Render an array to text */
static cJSON_bool print_array(const cJSON *const item, printbuffer *const output_buffer)
{unsigned char *output_pointer = NULL;size_t length = 0;cJSON *current_element = item->child;if (output_buffer == NULL){return false;}/* Compose the output array. *//* opening square bracket */output_pointer = ensure(output_buffer, 1);if (output_pointer == NULL){return false;}/*列表中括号前部分*/*output_pointer = '[';output_buffer->offset++;output_buffer->depth++;while (current_element != NULL){    /*子节点的value*/if (!print_value(current_element, output_buffer)){return false;}update_offset(output_buffer);if (current_element->next){length = (size_t)(output_buffer->format ? 2 : 1);output_pointer = ensure(output_buffer, length + 1);if (output_pointer == NULL){return false;}/*有下一个对象,则添加列表对象间分隔符*/*output_pointer++ = ',';if (output_buffer->format){*output_pointer++ = ' ';}*output_pointer = '\0';output_buffer->offset += length;}current_element = current_element->next;}output_pointer = ensure(output_buffer, 2);if (output_pointer == NULL){return false;}/*中括号后部分*/*output_pointer++ = ']';*output_pointer = '\0';output_buffer->depth--;return true;
}

输出为

[子节点值,子节点值]

 这都是从结果来推到需求,写代码时从需求到结果,其实更好的分析方法是想自己该如何实现它。

2.2.5.3 print_number
/* Render the number nicely from the given item into a string. */
static cJSON_bool print_number(const cJSON *const item, printbuffer *const output_buffer)
{unsigned char *output_pointer = NULL;double d = item->valuedouble;int length = 0;size_t i = 0;unsigned char number_buffer[26]; /* temporary buffer to print the number into */unsigned char decimal_point = get_decimal_point();double test;if (output_buffer == NULL){return false;}/* This checks for NaN and Infinity */if ((d * 0) != 0){length = sprintf((char *)number_buffer, "null");}else{/* Try 15 decimal places of precision to avoid nonsignificant nonzero digits */length = sprintf((char *)number_buffer, "%1.15g", d);/* Check whether the original double can be recovered */if ((sscanf((char *)number_buffer, "%lg", &test) != 1) || ((double)test != d)){/* If not, print with 17 decimal places of precision */length = sprintf((char *)number_buffer, "%1.17g", d);}}/* sprintf failed or buffer overrun occured */if ((length < 0) || (length > (int)(sizeof(number_buffer) - 1))){return false;}/* reserve appropriate space in the output */output_pointer = ensure(output_buffer, (size_t)length + sizeof(""));if (output_pointer == NULL){return false;}/* copy the printed number to the output and replace locale* dependent decimal point with '.' */for (i = 0; i < ((size_t)length); i++){if (number_buffer[i] == decimal_point){output_pointer[i] = '.';continue;}output_pointer[i] = number_buffer[i];}output_pointer[i] = '\0';output_buffer->offset += (size_t)i;return true;
}

 %1.15g

  • %:格式化输出的开始符号
  • 1.15:表示输出的总宽度为1,小数点后保留15位有效数字
  • g:以指数形式输出浮点数

 按上述获取长度后,从double类型的valuedouble中转化为字符串

2.3 解析JSON

涉及到函数有

  /*解析*/CJSON_PUBLIC(cJSON *)cJSON_Parse(const char *value);/*获取节点数目或节点*/CJSON_PUBLIC(int)cJSON_GetArraySize(const cJSON *array);/* Retrieve item number "item" from array "array". Returns NULL if unsuccessful. */CJSON_PUBLIC(cJSON *)cJSON_GetArrayItem(const cJSON *array, int index);/* Get item "string" from object. Case insensitive. */CJSON_PUBLIC(cJSON *)cJSON_GetObjectItem(const cJSON *const object, const char *const string);

 2.3.1 解析

/* Parse an object - create a new root, and populate. */
CJSON_PUBLIC(cJSON *)
cJSON_ParseWithOpts(const char *value, const char **return_parse_end, cJSON_bool require_null_terminated)
{parse_buffer buffer = {0, 0, 0, 0, {0, 0, 0}};cJSON *item = NULL;/* reset error position */global_error.json = NULL;global_error.position = 0;if (value == NULL){goto fail;}buffer.content = (const unsigned char *)value;buffer.length = strlen((const char *)value) + sizeof("");buffer.offset = 0;buffer.hooks = global_hooks;/*创建根节点*/item = cJSON_New_Item(&global_hooks);if (item == NULL) /* memory fail */{goto fail;}if (!parse_value(item, buffer_skip_whitespace(skip_utf8_bom(&buffer)))){/* parse failure. ep is set. */goto fail;}/* if we require null-terminated JSON without appended garbage, skip and then check for a null terminator */if (require_null_terminated){buffer_skip_whitespace(&buffer);if ((buffer.offset >= buffer.length) || buffer_at_offset(&buffer)[0] != '\0'){goto fail;}}if (return_parse_end){*return_parse_end = (const char *)buffer_at_offset(&buffer);}return item;fail:if (item != NULL){cJSON_Delete(item);}if (value != NULL){error local_error;local_error.json = (const unsigned char *)value;local_error.position = 0;if (buffer.offset < buffer.length){local_error.position = buffer.offset;}else if (buffer.length > 0){local_error.position = buffer.length - 1;}if (return_parse_end != NULL){*return_parse_end = (const char *)local_error.json + local_error.position;}global_error = local_error;}return NULL;
}CJSON_PUBLIC(cJSON *)
cJSON_Parse(const char *value)
{return cJSON_ParseWithOpts(value, 0, 0);
}

 核心还是来到了parse_value

/* Parser core - when encountering text, process appropriately. */
static cJSON_bool parse_value(cJSON *const item, parse_buffer *const input_buffer)
{if ((input_buffer == NULL) || (input_buffer->content == NULL)){return false; /* no input */}/* parse the different types of values *//* null */if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "null", 4) == 0)){item->type = cJSON_NULL;input_buffer->offset += 4;return true;}/* false */if (can_read(input_buffer, 5) && (strncmp((const char *)buffer_at_offset(input_buffer), "false", 5) == 0)){item->type = cJSON_False;input_buffer->offset += 5;return true;}/* true */if (can_read(input_buffer, 4) && (strncmp((const char *)buffer_at_offset(input_buffer), "true", 4) == 0)){item->type = cJSON_True;item->valueint = 1;input_buffer->offset += 4;return true;}/* string */if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '\"')){return parse_string(item, input_buffer);}/* number */if (can_access_at_index(input_buffer, 0) && ((buffer_at_offset(input_buffer)[0] == '-') || ((buffer_at_offset(input_buffer)[0] >= '0') && (buffer_at_offset(input_buffer)[0] <= '9')))){return parse_number(item, input_buffer);}/* array */if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '[')){return parse_array(item, input_buffer);}/* object */if (can_access_at_index(input_buffer, 0) && (buffer_at_offset(input_buffer)[0] == '{')){return parse_object(item, input_buffer);}return false;
}

 针对各自类型的特点开始解析,根据这里也没有啥特殊的,最终都化为字符串和数值。

2.3.2 获取节点数目

获取子节点的个数,子节点链表中对象数目。

2.3.3 获取节点

只能获取子节点的信息,采取一级一级剥洋葱的方式。

3、添加对long long类型的支持

有博主是在cJSON_NUM类型下开了个子类型,逻辑也是相当清晰,本文在大的类型里添加。

没有啥难度,照葫芦画瓢,把类型和标志的意义搞懂就没出过BUG了。

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

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

相关文章

【计算机设计大赛作品】豆瓣电影数据挖掘可视化—信息可视化赛道获奖项目深入剖析【可视化项目案例-22】

文章目录 一.【计算机设计大赛作品】豆瓣电影数据挖掘可视化—信息可视化赛道获奖项目深入剖析【可视化项目案例-22】1.1 项目主题:豆瓣电影二.代码剖析2.1 项目效果展示2.2 服务端代码剖析2.3 数据分析2.4 数据评分三.寄语四.本案例完整源码下载一.【计算机设计大赛作品】豆瓣…

频率域图像增强之理想低通滤波器的python实现——数字图像处理

原理 理想低通滤波器&#xff08;Ideal Low-Pass Filter, ILPF&#xff09;是数字图像处理中一个重要的概念&#xff0c;尤其在频率域滤波中扮演着关键角色。 定义&#xff1a; 理想低通滤波器是一种在频率域内工作的滤波器&#xff0c;旨在通过允许低频信号通过同时阻止高频信…

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解

时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解 目录 时序分解 | Matlab实现贝叶斯变化点检测与时间序列分解效果一览基本介绍程序设计参考资料 效果一览 基本介绍 Matlab实现贝叶斯变化点检测与时间序列分解 1.Matlab实现贝叶斯变化点检测与时间序列分解&#xff0c;完…

数据中心网络架构

参考&#xff1a; 一文读懂胖树 数据中心网络架构VL2详解 数据中心网络拓扑设计目标 总体目标 业务可以部署在任意的服务器上可以根据需要动态扩展或者缩小服务器规模 网络角度 均衡负载且高性能&#xff1a;服务器之间的性能仅受限于服务器网卡&#xff0c;而不是链路性能…

【Java】SpringBoot整合xxl-job学习使用详解

文章目录 介绍作用如何使用下载项目中央仓库地址环境调度中心初始化“调度数据库”配置部署“调度中心”部署项目调度中心集群&#xff08;可选&#xff09;其他&#xff1a;Docker 镜像方式搭建调度中心配置部署“执行器项目” 执行器maven依赖执行器配置执行器组件配置执行器…

【userfaultfd 条件竞争】starCTF2019 - hackme

前言 呜呜呜&#xff0c;这题不难&#xff0c;但是差不多一个多月没碰我的女朋友 kernel pwn 了&#xff0c;对我的 root 宝宝也是非常想念&#xff0c;可惜这题没有找到我的 root 宝宝&#xff0c;就偷了她的 flag。 哎有点生疏了&#xff0c;这题没看出来堆溢出&#xff0c…

Linux引导过程与服务控制

目录 一、操作系统引导过程 1. 过程图示 2. 步骤解析 2.1 bios 2.2 mbr 2.3 grup 2.4 加载内核文件 3. 过程总结 4. centos6和centos7启动区别 5. 小结 二、服务控制及切换运行级别 1. systemd核心概念 2. 运行级别 3. Systemd单元类型 4. 运行级别所对应的Syst…

基于YOLOv8深度学习的人脸面部表情识别系统【python源码+Pyqt5界面+数据集+训练代码】深度学习实战

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推…

js文件上传 分片上传/断点续传/极速秒传

(极速秒传)利用md5判断上传的文件是否存在 MD5信息摘要算法&#xff0c;一种被广泛使用的密码散列函数&#xff0c;可以产生出一个128位&#xff08;16字节&#xff09;的散列值&#xff08;hash value&#xff09;&#xff0c;用于确保信息传输完整一致。 每一个文件都会生成…

对接第三方接口鉴权(Spring Boot+Aop+注解实现Api接口签名验证)

前言 一个web系统&#xff0c;从接口的使用范围也可以分为对内和对外两种&#xff0c;对内的接口主要限于一些我们内部系统的调用&#xff0c;多是通过内网进行调用&#xff0c;往往不用考虑太复杂的鉴权操作。但是&#xff0c;对于对外的接口&#xff0c;我们就不得不重视这个…

Elasticsearch:结合 ELSER 和 BM25 文本查询的相关搜索

Elastic Learned Spare EncodeR (ELSER) 允许你执行语义搜索以获得更相关的搜索结果。 然而&#xff0c;有时&#xff0c;将语义搜索结果与常规关键字搜索结果相结合以获得最佳结果会更有用。 问题是&#xff0c;如何结合文本和语义搜索结果&#xff1f; 首先&#xff0c;让我…

Java异常篇----第二篇

系列文章目录 文章目录 系列文章目录前言一、 Excption与Error包结构二、Thow与thorws区别三、Error与Exception区别?四、error和exception有什么区别前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站,这篇文章男女…

1213:八皇后问题 深度优先搜索算法

1213&#xff1a;八皇后问题 时间限制: 1000 ms 内存限制: 65536 KB 【题目描述】 在国际象棋棋盘上放置八个皇后&#xff0c;要求每两个皇后之间不能直接吃掉对方。 【输入】 (无) 【输出】 按给定顺序和格式输出所有八皇后问题的解&#xff08;见样例&#xff09;。 题目…

Spring源码之依赖注入(二)

书接上文 文章目录 一. Autowire底层注入逻辑1. 属性注入逻辑 一. Autowire底层注入逻辑 前面我们分析了Spring时如何找到某个目标类的所有注入点这一个核心逻辑&#xff0c;但还没又对核心注入方法inject进行详细分析&#xff0c;下面我们就来详细分析Spring拿到所有的注入点…

【CASS精品教程】CASS11计算城镇建筑密度

CASS中可以很方便计算建筑密度。 文章目录 一、建筑密度介绍二、CASS计算建筑密度1. 绘制宗地范围2. 绘制建筑物3. 计算建筑密度三、注意事项一、建筑密度介绍 建筑密度(building density;building coverage ratio),指在一定范围内,建筑物的基底面积总和与占用地面积的比…

纠删码ReedSolomon

随着大数据技术的发展&#xff0c;HDFS作为Hadoop的核心模块之一得到了广泛的应用。为了数据的可靠性&#xff0c;HDFS通过多副本机制来保证。在HDFS中的每一份数据都有两个副本&#xff0c;1TB的原始数据需要占用3TB的磁盘空间&#xff0c;存储利用率只有1/3。而且系统中大部分…

Spring Boot 2.7.11 集成 GraphQL

GraphQL介绍 GraphQL&#xff08;Graph Query Language&#xff09;是一种用于API的查询语言和运行时环境&#xff0c;由Facebook于2012年创建并在2015年公开发布。与传统的RESTful API相比&#xff0c;GraphQL提供了更灵活、高效和强大的数据查询和操作方式。 以下是GraphQL…

Spring技术内幕笔记之SpringMvc

WebApplicationContext接口的类继承关系 org.springframework.web.context.ContextLoader#initWebApplicationContext 对IOC容器的初始化 SpringMvc如何设计 DispatcherServlet类继承关系 MVC处理流程图如下&#xff1a; DispatcherServlet的工作大致可以分为两个部分&#xf…

NFC物联网开发智能衣橱解决方案

智能衣橱是智能家居的重要内容&#xff0c;现代家居市场对家居智能化控制尤为重视。但是&#xff0c;传统家居生产功能和模式已经无法满足智能化时代的需求&#xff0c;所以家居智能化成为家居行业发展的主要需求。与传统衣橱对比&#xff0c;智能衣橱的功能强大方便人们的生活…

Android--Jetpack--WorkManager详解

2024已经到来&#xff0c;愿你安睡时&#xff0c;山河入梦。愿你醒来时&#xff0c;满目春风。愿你欢笑时&#xff0c;始终如一。愿你行进时&#xff0c;前程似锦&#xff0c;坦荡从容。 编程语言的未来&#xff1f; 目录 一&#xff0c;定义 二&#xff0c;特点 三&#xff0c…