C语言JSON序列化反序列化工具库
cJSONx是依赖于cJSON解析库的二次封装库,实现快速、灵活地对在C语言结构体(struct)与JSON字符串之间转换
cJSONx GIT仓库传送门
文章目录
1. 前言
C语言是嵌入式领域为数不多的选择之一,现代嵌入式应用当中又有很多业务逻辑会涉及到JSON转换的需求,此工具库依赖于C语言JSON解析库cJSON,编写cJSONx的目的是实现相对优雅地对JSON字符串进行正反序列化。
2 参考
本工具库实现参考了
3 实现目标
cJSONx的目标就是最大化简化相关业务逻辑代码,实现的模式基本上就是参照Java谷歌GSON,通过类反射机制进行数据读写,使用@Expose
、@SerializedName
等注解实现一些基本的正反序列化规定,关于GSON的使用不再赘述。
4 使用简介
cJSONx参考了一部分cson的实现,做了一些拓展和完善,在宏API设计上进行了完善。
cJSONx支持对c语言所有基本类型的反射,包括不同长度的整型和float、double两种浮点类型。
cJSONx支持ptr
反射和preallocated
反射,使用时选用不同的宏来声明当前field是否需要申请空间,ptr
反射会通过依赖库cJSON中cJSON_Hooks
指定的内存申请、释放函数进行内存分配释放操作(默认为标准库的malloc
,free
),preallocated
反射则用于静态内存field。
4.1 宏API
注意,函数名字中不带有ptr的声明均用于静态内存声明。
4.1.1 基础类型反射
__cjsonx_int(type, field) // 对应 1,2,4,8任意字节长度整型
__cjsonx_real(type, field) // 对应 float 或者 double
__cjsonx_bool(type, field) // 对应 bool, 或者任意整型
__cjsonx_str(type, field) // 对应字符数组 char c[20]
__cjsonx_str_ptr(type, field) // 对应字符指针 char* str
__cjsonx_object(type, field, reflect) // 对应结构体
__cjsonx_object_ptr(type, field, reflect) // 对应结构体指针
4.1.2 静态Array反射
__cjsonx_array_int(type, field, item_count_field) // 对应任意整型数组
__cjsonx_array_real(type, field, item_count_field) // 对应任意浮点型数组
__cjsonx_array_bool(type, field, item_count_field) // 对应bool数组或者整型数组
__cjsonx_array_str_ptr(type, field, item_count_field) // 对应字符指针数组, char* strs[10]
__cjsonx_array_str(type, field, item_count_field) // 对应 char[20][50]
__cjsonx_array_object(type, field, item_count_field, refelct) // 对应结构体数组
4.1.3 指针(动态内存)Array反射
__cjsonx_array_ptr_int(type, field, item_count_field) // 8/16/32/64位int* arr_i
__cjsonx_array_ptr_real(type, field, item_count_field) // float/double* arr_d
__cjsonx_array_ptr_bool(type, field, item_count_field) // bool* arr_b
__cjsonx_array_ptr_str_ptr(type, field, item_count_field) // char** strs
__cjsonx_array_ptr_object(type, field, item_count_field, refelct) // 结构体指针
4.1.4 扩展注解的反射
__cjsonx_int_ex(type, field, annotations...)
__cjsonx_real_ex(type, field, annotations...)
__cjsonx_bool_ex(type, field, annotations...)
__cjsonx_str_ex(type, field, annotations...)
__cjsonx_str_ptr_ex(type, field, annotations...)
__cjsonx_object_ex(type, field, reflect, annotations...)
__cjsonx_object_ptr_ex(type, field, reflect, annotations...)
__nullable(__val) // 注解此field不可为空
__deserialized(__val) // 注解此field是否反序列化
__serialized(__val) // 注解此field是否序列化
__serialized_name(__name) // 注解此field序列化名
...
4.1.5 正反序列化API
/**
* Convert Json string to struct
*
* @param jstr Json string
* @param output Struct address
* @param tbl Reflection table
* @return Error code
*/
int cjsonx_str2struct(const char* jstr, void* output, const cjsonx_reflect_t* tbl);
/**
* Convert Json string with length to struct
*
* @param jstr Json string preallocated
* @param len Buffer length
* @param output Struct address
* @param tbl Reflection table
* @return Error code
*/
int cjsonx_nstr2struct(const char* jstr, size_t len, void* output, const cjsonx_reflect_t* tbl);
/**
* Convert cJSON object to struct
*
* @param jo Json object
* @param output Struct address
* @param tbl Reflection table
* @return Error code
*/
int cjsonx_obj2struct(cJSON* jo, void* output, const cjsonx_reflect_t* tbl);
/**
* Convert struct to json (string allocated)
*
* @param jstr Pointer to place string address
* @param input Struct address
* @param tbl Reflection table
* @return error code
*/
int cjsonx_struct2str(char** jstr, void* input, const cjsonx_reflect_t* tbl);
/**
* Convert struct to json (char buffer preallocated)
*
* @param jstr String buffer
* @param size Buffer size
* @param input Struct address
* @param tbl Reflection table
* @return error code
*/
int cjsonx_struct2str_preallocated(char* jstr, const int size, void* input, const cjsonx_reflect_t* tbl);
/**
* Convert struct to cJSON object
*
* @param obj cJSON object
* @param input Struct address
* @param tbl Reflection table
* @return error code
*/
int cjsonx_struct2obj(cJSON* obj, void* input, const cjsonx_reflect_t* tbl);
4.2 使用实例
4.2.1 简单使用
使用反射的第一步要声明结构体的反射,声明的方式是构建一个不定长反射数组cjsonx_reflect_t device_reflection[]
来获取结构体域内存的反射数据,反射数组成员则是前面介绍以双下划线开头的的反射宏函数
,声明完成后直接调用正反序列化转换函数完成转换。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "cJSONx.h"
struct device {
int id;
char name[20];
float temprature;
unsigned long tick;
unsigned int ip;
unsigned int netmask;
unsigned int gateway;
};
const cjsonx_reflect_t device_reflection[] = {
__cjsonx_int(struct device, id),
__cjsonx_str(struct device, name),
__cjsonx_real(struct device, temprature),
__cjsonx_int(struct device, tick),
__cjsonx_int(struct device, ip),
__cjsonx_int(struct device, netmask),
__cjsonx_int(struct device, gateway),
__cjsonx_end()
};
static void simple_serialize();
static void simple_deserialize();
int main(int argc, char* argv[]) {
simple_serialize();
simple_deserialize();
}
void simple_serialize() {
struct device d = {
.id = 1,
.ip = 0x0A01A8C0,
.gateway = 0x0101A8C0,
.netmask = 0x00FFFFFF,
.name = "Hello World",
.temprature = 36.2F,
.tick = 123
};
char buf[300];
int ret = cjsonx_struct2str_preallocated(buf, sizeof(buf), &d, device_reflection);
if (ret == ERR_CJSONX_NONE) {
printf("Serialized JSON string: %s\n", buf