当前位置:网站首页>cJSON库的使用
cJSON库的使用
2022-07-23 19:35:00 【柿子风年】
MQTT+JSON是物联网设备进行数据交互最常用的通讯协议,其中JSON协议非常适合用于明文传输、短包传输的场景。
认识理解和运用设计一个协议,一定要先了解其原理,再去认识其优缺点和适用范围。
目录
1、JSON概念表述
JSON数据结构是一个键值对的序列化对象或数组。
键,是一个字符串;
值,可以是对象,数组,数字,字符串其中的一种;
其中对象由花括号括起来并用逗号进行分割;
数组是由方括号括起来的,字符串是由双引号包围的,二者都由逗号分隔;
数字不需要括起来,直接用逗号分隔。
其本质就是一个字符串,可以跨语言、跨平台进行存储,并且字符串key-value的形式方便阅读。
cJSON库就是一种最典型的C语言JSON库代码。
非常适合在嵌入式设备上移植和使用。
2、cJSON库可能需要的修改
2.1 内存修改
该库默认使用的C标准库的内存函数。
如果你需要调试内存问题,或者需要统一内存使用方式,都可以更改如下位置的代码替换内存函数。
#if defined(_MSC_VER)
/* work around MSVC error C2322: '...' address of dllimport '...' is not static */
static void * CJSON_CDECL internal_malloc(size_t size)
{
return malloc(size);
}
static void CJSON_CDECL internal_free(void *pointer)
{
free(pointer);
}
static void * CJSON_CDECL internal_realloc(void *pointer, size_t size)
{
return realloc(pointer, size);
}
#else
#define internal_malloc malloc
#define internal_free free
#define internal_realloc realloc
#endif2.2 打印number出现的科学计数法(参考)
static cJSON_bool print_number(const cJSON * const item, printbuffer * const output_buffer);
文件第511行,该函数执行sscanf之后,会出现导致打印number类型数值,结果出现科学计数法的问题(stm32F205芯片调试时出现的,当时内存资源极度紧张)。
修改方案如下(修改后解决):
具体原因我也没搞清楚,就先列一下解决方案。
#if 0
/* 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) || !compare_double((double)test, d))
{
/* If not, print with 17 decimal places of precision */
length = sprintf((char*)number_buffer, "%1.17g", d);
}
#else
length = sprintf((char*)number_buffer, "%d", (unsigned int)d);
#endif3、JSON解析和处理的一般方法
3.1 定义
//头文件的必要包含关系和声明
#include "cJSON.h"
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
typedef enum
{
ERROR_CODE_INTER = -1, //内部错误
ERROR_CODE_NONE = 0, //空/OK
ERROR_CODE_PARAM, //参数错误
} EnErrorCode;
typedef struct
{
char *CmdStr;
int (*CmdFun)(cJSON*);
} TyJsonCmdFun;
void JsonCmdAnalysis(uint8_t *pData, uint16_t unDataLen);
void JsonCmdResponse(cJSON *Json, int err, void *res);
void JsonCmdSend(uint8_t *pData, uint16_t unDataLen);如上,定义了①函数返回的错误码,②json函数结构体,③函数解析和反馈的入口。
3.2 解析JSON
基于此,可以定义如下的函数表,
收到数据去解析时,判断json的固定键值对-如"cmd"字段,来执行对应的处理函数。
这里需要注意一个点:cJSON_Parse和cJSON_Delete。
cJSON_Parse函数用于将字节流转成JSON对象,其中存在内存申请动作,且无法通过free进行释放,只能通过cJSON_Delete进行释放。
int JsonCmdDeal_version(cJSON *Json);
int JsonCmdDeal_ota_start(cJSON *Json);
int JsonCmdDeal_ota_data(cJSON *Json);
int JsonCmdDeal_ota_end(cJSON *Json);
int JsonCmdDeal_driver_test(cJSON *Json);
const static TyJsonCmdFun JsonCmdFunTable[] =
{
{"version", JsonCmdDeal_version},
{"ota_start", JsonCmdDeal_ota_start},
{"ota_data", JsonCmdDeal_ota_data},
{"ota_end", JsonCmdDeal_ota_end},
{"driver_test", JsonCmdDeal_driver_test},
};
void JsonCmdAnalysis(uint8_t *pData, uint16_t unDataLen)
{
uint8_t i;
cJSON *JsonCmd = NULL;
JsonCmd = cJSON_Parse((char*)pData);
if(JsonCmd != NULL)
{
for(i=0;i<sizeof(JsonCmdFunTable)/sizeof(TyJsonCmdFun);i++)
{
if(strcmp(JsonCmdFunTable[i].CmdStr,cJSON_GetObjectItem(JsonCmd,"cmd")->valuestring) == 0)
{
JsonCmdFunTable[i].CmdFun(JsonCmd);
break;
}
}
cJSON_Delete(JsonCmd);
}
}3.2 反馈/生成JSON
void JsonCmdResponse(cJSON *Json, int err, void *res)
{
char *json_buf = NULL;
int buf_len = 0;
cJSON* respond_json = NULL;
respond_json = cJSON_CreateObject();
if(respond_json != NULL)
{
cJSON_AddStringToObject(respond_json, "cmd", cJSON_GetObjectItem(Json,"cmd")->valuestring);
if(err == ERROR_CODE_NONE)
cJSON_AddStringToObject(respond_json, "rsq", "ok");
else
cJSON_AddNumberToObject(respond_json, "rsq", err);
json_buf = cJSON_PrintUnformatted(respond_json);
if(json_buf != NULL)
{
buf_len = strlen((char*)json_buf);
JsonCmdSend((uint8_t *)json_buf, buf_len);
free(json_buf);
}
cJSON_Delete(respond_json);
}
}
void JsonCmdSend(uint8_t *pData, uint16_t unDataLen)
{
//do nothing
}
int JsonCmdDeal_version(cJSON *Json)
{
int err = ERROR_CODE_NONE;
JsonCmdResponse(Json, err, NULL);
return err;
}同样的,cJSON_CreateObject() 函数用于创建JSON对象,并随着后面用户调用cJSON_AddXXXXToObject类的函数产生内存申请(realloc),最终只能由cJSON_Delete释放内存。
额外的一点,就是cJSON的print函数,是可以直接由free函数进行释放的。
其中,cJSON_PrintUnformatted是将JSON对象打印成无格式化字符的字符串。
cJSON_Print则是带有格式化字符的(会带有很多的空格与换行)。
如果需要直观查看JSON数据,建议用cJSON_Print;
但是如果是应用业务执行,建议还是用cJSON_PrintUnformatted,尽可能减少字节量传输。
3.4 经常用到的JSON处理函数
//内存操作函数
CJSON_PUBLIC(cJSON *) cJSON_Parse(const char *value);//字符串转json
CJSON_PUBLIC(char *) cJSON_Print(const cJSON *item);//打印json字符串1
CJSON_PUBLIC(char *) cJSON_PrintUnformatted(const cJSON *item);//打印json字符串2
CJSON_PUBLIC(void) cJSON_Delete(cJSON *item);//释放json
//创建json对象
CJSON_PUBLIC(cJSON *) cJSON_CreateObject(void);//创建json对象
CJSON_PUBLIC(cJSON *) cJSON_CreateArray(void);//创建数组
//创建json对象-用于更新键值对
CJSON_PUBLIC(cJSON *) cJSON_CreateNumber(double num);
CJSON_PUBLIC(cJSON *) cJSON_CreateString(const char *string);
CJSON_PUBLIC(cJSON *) cJSON_CreateTrue(void);
CJSON_PUBLIC(cJSON *) cJSON_CreateFalse(void);
//获取json对象
CJSON_PUBLIC(int) cJSON_GetArraySize(const cJSON *array);//获取数组大小
CJSON_PUBLIC(cJSON *) cJSON_GetArrayItem(const cJSON *array, int index);//获取数组的某一元素
CJSON_PUBLIC(cJSON *) cJSON_GetObjectItem(const cJSON * const object, const char * const string);//获取键值对
//添加json键值对
CJSON_PUBLIC(cJSON*) cJSON_AddObjectToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddArrayToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddTrueToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddFalseToObject(cJSON * const object, const char * const name);
CJSON_PUBLIC(cJSON*) cJSON_AddNumberToObject(cJSON * const object, const char * const name, const double number);
CJSON_PUBLIC(cJSON*) cJSON_AddStringToObject(cJSON * const object, const char * const name, const char * const string);
//判断键值对的值的类型
CJSON_PUBLIC(cJSON_bool) cJSON_IsNumber(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsString(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsArray(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsFalse(const cJSON * const item);
CJSON_PUBLIC(cJSON_bool) cJSON_IsTrue(const cJSON * const item);
//替换(更新)键值对
CJSON_PUBLIC(void) cJSON_ReplaceItemInArray(cJSON *array, int which, cJSON *newitem);
CJSON_PUBLIC(void) cJSON_ReplaceItemInObject(cJSON *object,const char *string,cJSON *newitem);
边栏推荐
- 关于网段CIDR的笔记
- What antenna is used for ant interface_ There is an interface at the back of the TV that says standard ant 75 Euro input. What does it mean, antenna? Can you connect the closed route "Suggested collec
- 【C语言】通讯录(静态版本)
- 数组——11. 盛最多水的容器
- Compiler llvm MLIR introductions llvm backend instruction
- 2022/7/21训练总结
- Prepare for pressure test with JMeter and visualvw
- 20. Valid Parentheses有效的括号
- 如何给电脑系统重置系统?方法其实很简单
- Mecol Studio - Little Bear Development Notes 3
猜你喜欢

Win11没有Word文档怎么办?Win11没有Word文档解决教程

能量原理与变分法笔记19:最小余能原理+可能功原理

2022DASCTF MAY

How to reset the computer system? The method is actually very simple

MongoDB-查询语句中$exists以及结合$ne、$nin、$nor、$not使用介绍

Leetcode 151. invert words in strings

如何合理地估算线程池大小

【AR学习】-- 二、 环境搭建
![[interview: concurrent Article 22 multithreading: reentrantlock]](/img/a7/19f947faba18e58b768588af414aeb.png)
[interview: concurrent Article 22 multithreading: reentrantlock]

能量原理與變分法筆記19:最小餘能原理+可能功原理
随机推荐
C language leak detection and filling (1)
剑指 Offer II 115. 重建序列
Leetcode 152. 乘积最大子数组(暴力破解居然可以通过!)
Detailed writing process of impala
Osgearth2.8 compiling silvering cloud effect
2022/7/22 训练日志
[PM2] PM2 common commands
Debian | Can’t locate Debian/Debhelper/Sequence/germinate.pm in @INC
phar反序列化
21. Mix in details
Non local mean filtering / attention mechanism
What antenna is used for ant interface_ There is an interface at the back of the TV that says standard ant 75 Euro input. What does it mean, antenna? Can you connect the closed route "Suggested collec
深入浅出边缘云 | 1. 概述
Edge cloud | 1. overview
2022 Shandong old age Expo, Shandong elderly care exhibition, China International elderly care service industry exhibition was held in September
Energy principle and variational method note 16: solution of virtual displacement principle
Win11没有Word文档怎么办?Win11没有Word文档解决教程
Leetcode - the nearest sum of three numbers
梅科爾工作室-小熊派開發筆記2
20. Valid Parentheses有效的括号