Skip to content

Cpp struct2json #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 14 commits into
base: master
Choose a base branch
from
29 changes: 17 additions & 12 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
# C结构体与 JSON 快速互转库
# C&C++结构体与 JSON 快速互转库

---

## struct2json

[struct2json](https://github.com/armink/struct2json) 是一个开源的C结构体与 JSON 快速互转库,它可以快速实现 **结构体对象** 与 **JSON 对象** 之间序列化及反序列化要求。快速、简洁的 API 设计,大大降低直接使用 JSON 解析库来实现此类功能的代码复杂度。
[struct2json](https://github.com/armink/struct2json) 是一个开源的C&C++结构体与 JSON 快速互转库,它可以快速实现 **结构体对象** 与 **JSON 对象** 之间序列化及反序列化要求。快速、简洁的 API 设计,大大降低直接使用 JSON 解析库来实现此类功能的代码复杂度。

## 起源

把面向对象设计应用到C语言中,是当下很流行的设计思想。由于C语言中没有类,所以一般使用结构体 `struct` 充当类,那么结构体变量就是对象。有了对象之后,很多时候需要考虑对象的序列化及反序列化问题。C语言不像很多高级语言拥有反射等机制,使得对象序列化及反序列化被原生的支持。
C&C++对象的序列化及反序列化问题解决方案(由于C语言中没有类,所以一般使用结构体 `struct` 充当类,那么结构体变量就是对象)。
C&C++语言不像很多高级语言拥有反射等机制,使得对象序列化及反序列化被原生的支持。
对于C&C++语言来说,序列化为 JSON 字符串是个不错的选择,所以就得使用 [cJSON](https://github.com/kbranigan/cJSON) 这类 JSON 解析库,但是使用后的代码冗余且逻辑性差,所以萌生对cJSON库进行二次封装,实现一个 struct 与 JSON 之间快速互转的库。 struct2json 就诞生于此。下面是 struct2json 主要使用场景:

对于C语言来说,序列化为 JSON 字符串是个不错的选择,所以就得使用 [cJSON](https://github.com/kbranigan/cJSON) 这类 JSON 解析库,但是使用后的代码冗余且逻辑性差,所以萌生对cJSON库进行二次封装,实现一个 struct 与 JSON 之间快速互转的库。 struct2json 就诞生于此。下面是 struct2json 主要使用场景:

- **持久化** :结构体对象序列化为 JSON 对象后,可直接保存至文件、Flash,实现对结构体对象的掉电存储;
- **通信** :高级语言对JSON支持的很友好,例如: Javascript、Groovy 就对 JSON 具有原生的支持,所以 JSON 也可作为C语言与其他语言软件之间的通信协议格式及对象传递格式;
- **持久化** :结构体对象序列化为 JSON 对象后,可直接保存至文件、Flash,实现对结构体对象的持久化存储;
- **通信** :高级语言对JSON支持的很友好,例如: Javascript、Groovy 就对 JSON 具有原生的支持,所以 JSON 也可作为C&C++语言与其他语言软件之间的通信协议格式及对象传递格式;
- **可视化** :序列化为 JSON 后的对象,可以更加直观的展示到控制台或者 UI 上,可用于产品调试、产品二次开发等场景;

## 如何使用
Expand Down Expand Up @@ -50,12 +50,15 @@ typedef struct {
|:-----:|:-----:|
|![JSON转结构体-使用前](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/not_use_struct2json_for_json.png)| ![JSON转结构体-使用后](https://git.oschina.net/Armink/struct2json/raw/master/docs/zh/images/used_struct2json_for_json.png)|

### V2.0版本新增功能【yuxuebao】
#### 1) 更新cJSON库至1.7.12版本,并扩充实现,支持int64 (long long)类型数据。PS:cJSON原来int64类型以double方式处理,如果超过16位会有精度损失。
### V2.0版本新增功能【yuxuebao@msn.com
#### 1) 更新cJSON库至1.7.14版本,并扩充实现,支持int64 (long long)类型数据。PS:cJSON原来int64类型以double方式处理,如果超过16位会有精度损失。
#### 2) 扩展struct2json功能,增加支持结构体内包含结构体成员,支持包含数组成员。
#### 3) 增加struct2json 结构体与JSON转换代码自动生成的Python脚本,支持从头文件中提取结构体定义,并根据结构体定义自动生成结构体与JSON互转代码,并提供相关示例。

### V2.0 使用说明:
### V2.1版本新增功能【[email protected]
#### 1) 扩展struct2json功能,增加支持C++结构体,支持string,bool,wchar_t类型成员和数组。

### V2.x 使用说明:
#### 1) 提取结构体定义:
将头文件(eg:mc_usr_def.h)放在demo\inc目录下;
执行generate_struct_defination.py,生成struct_defination.txt;
Expand All @@ -65,10 +68,12 @@ typedef struct {
支持的数组类型:支持基本类型一维数组,结构体一维数组,字符二维数组(字符串数组)
#### 3) 测试结构体与JSON转换:
cd demo
编译测试代码,gcc ../cJSON/cJSON.c ../struct2json/src/*.c ./*.c -I ../cJSON/ -I ../struct2json/inc/ -lm -DDEBUGS2J -g -o tests2j
编译测试代码,
V2.0: gcc ../cJSON/cJSON.c ../struct2json/src/*.c ./*.c -I ../cJSON/ -I ../struct2json/inc/ -lm -g -DDEBUGS2J -o tests2j
V2.1+: g++ ../cJSON/cJSON.c ../struct2json/src/*.c ./*.c -I ../cJSON/ -I ../struct2json/inc/ -fpermissive -lm -g -DDEBUGS2J -o tests2j
测试 ./tests2j
查看output输出和生成的JSON样例文件struct_defination.json;
预期输出:*:strcmp:0 *:strcmp:0*:json_cmp:1
预期输出:*:strcmp:0 *:strcmp:0 *:json_cmp:1

欢迎大家 **fork and pull request**([Github](https://github.com/armink/struct2json)|[OSChina](http://git.oschina.net/armink/struct2json)|[Coding](https://coding.net/u/armink/p/struct2json/git)) 。如果觉得这个开源项目很赞,可以点击[项目主页](https://github.com/armink/struct2json) 右上角的**Star**,同时把它推荐给更多有需要的朋友。

Expand Down
2 changes: 2 additions & 0 deletions demo/error_print.txt
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
struct_para_json2bin(CppStructInfoT,bin_para,type,value)
struct_para_json2bin(McUsrInfoT,bin_para,type,value)
struct_para_json2bin(McBaseOrdrT,bin_para,type,value)
struct_para_json2bin(McBaseOrdrArrayT,bin_para,type,value)
struct_para_json2bin(McOcoBaseOrdrT,bin_para,type,value)

*************************************
struct_para_bin2json(CppStructInfoT,bin_para,type,json_para)
struct_para_bin2json(McUsrInfoT,bin_para,type,json_para)
struct_para_bin2json(McBaseOrdrT,bin_para,type,json_para)
struct_para_bin2json(McBaseOrdrArrayT,bin_para,type,json_para)
Expand Down
62 changes: 44 additions & 18 deletions demo/generate_s2j_code.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,10 @@
#print(array_para_name_size)
para_name = para_name.split("[")[0]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, int, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_array_element(struct_obj_,json_obj, int, "+para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, int, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+para_name+");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+ para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+ para_name+");\n\t"
elif para_type.find("enum")!=-1 or para_type.find("CbT")!=-1: # enum或函数指针(根据实际命名规范识别)
#print(para_type)
if "[" in para_name:
Expand All @@ -85,38 +85,52 @@
#print(array_para_name_size)
para_name = para_name.split("[")[0]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, int, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_array_element(struct_obj_,json_obj, int, "+para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, int, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+para_name+");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+ para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+ para_name+");\n\t"
elif para_type in ("string","std::string"): #c++ std::string
if "[" in para_name: # 处理c++ std::string数组的情况
#print(para_name)
left_symbol = para_name.find("[") # 找到[位置
right_symbol = para_name.find("]") # 找到]位置
array_para_name_size = para_name[left_symbol+1:right_symbol]
#print(array_para_name_size)
para_name = para_name.split("[")[0]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, stdstring, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, stdstring, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, stdstring, " + para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, stdstring, " + para_name + ");\n\t"
else: #基本类型
if para_type in ("char","unsigned char","signed char","int","unsigned","unsigned int","signed int","short","unsigned short","signed short","long","unsigned long","signed long","long long","unsigned long long","signed long long","BOOL","bool","size_t","uint8_t","uint16_t","uint32_t","uint64_t","int8_t","int16_t","int32_t","int64_t","uint8","uint16","uint32","uint64","int8","int16","int32","int64","uint_fast64_t","__int128_t","__uint128_t","float","double","long double"):
if para_type in ("bool", "wchar_t", "char","unsigned char","signed char","int","unsigned","unsigned int","signed int","short","unsigned short","signed short","long","unsigned long","signed long","long long","unsigned long long","signed long long","BOOL","bool","size_t","uint8_t","uint16_t","uint32_t","uint64_t","int8_t","int16_t","int32_t","int64_t","uint8","uint16","uint32","uint64","int8","int16","int32","int64","uint_fast64_t","__int128_t","__uint128_t","float","double","long double"):
if para_type in ("float","double","long double","__int128_t","__uint128_t"): #浮点型、128位整型
if "[" in para_name:
#print(para_name)
left_symbol = para_name.find("[") # 找到[位置
right_symbol = para_name.find("]") # 找到]位置
array_para_name_size = para_name[left_symbol+1:right_symbol]
#print(array_para_name_size)
para_name = para_name.split("[")[0]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, double, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_array_element(struct_obj_,json_obj, double, "+para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, double, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, double, "+para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_basic_element(struct_obj_,json_obj, double, "+para_name+");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, double, "+ para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, double, "+ para_name+");\n\t"
elif para_type =="char" : # 字符串
if "[" in para_name:
para_name_item = para_name.split("[")
if len(para_name_item)==2: # 处理字符数组的情况,只取名字,舍弃中括号部分
para_name = para_name_item[0]
s2j_code_str_concat = s2j_code_str_concat+ "s2j_json_set_basic_element(json_obj_, struct_obj_, string, " + para_name + ");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, string, " + para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, string, " + para_name + ");\n\t"
elif len(para_name_item)==3: # 处理二维字符数组的情况
para_name = para_name_item[0]
# left_symbol = 0 # 找到[位置
right_symbol = para_name_item[1].find("]") # 找到]位置
array_para_name_size = para_name_item[1][0:right_symbol]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, string, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_array_element(struct_obj_,json_obj, string, "+para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, string, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, " + para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, " + para_name + ");\n\t"
Expand All @@ -129,10 +143,10 @@
#print(array_para_name_size)
para_name = para_name.split("[")[0]
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_array_element(json_obj_, struct_obj_, int, "+ para_name + ","+ array_para_name_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_array_element(struct_obj_,json_obj, int, "+para_name + ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_array_element(struct_obj_,json_obj, int, "+ para_name + ");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat +"s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+para_name+");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_basic_element(json_obj_, struct_obj_, int, "+ para_name+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_basic_element(struct_obj_,json_obj, int, "+ para_name+");\n\t"
else: #结构体类型的参数
if "[" in para_name:
# usrDefLst[MAX_LIST_MEM_TYPE]
Expand All @@ -143,7 +157,7 @@
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_struct_array_element_by_func(json_obj_, struct_obj_, "+ para_type +","+para_name+ ","+list_size+");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_struct_array_element_by_func(struct_obj_, json_obj, "+ para_type +","+para_name+");\n\t"
else:
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_struct_element_by_func(json_obj_, struct_obj_, "+ para_type +","+para_name+ ");\n\t"
s2j_code_str_concat = s2j_code_str_concat + "s2j_json_set_struct_element_by_func(json_obj_, struct_obj_, " + para_type +","+para_name+ ");\n\t"
j2s_code_str_concat = j2s_code_str_concat + "s2j_struct_get_struct_element_by_func(struct_obj_, json_obj, " + para_type + "," + para_name + ");\n\t"

s2j_code_str_concat_return = s2j_code_str_concat_return + s2j_code_str_concat # #"return json_obj_;\n}"
Expand Down Expand Up @@ -199,13 +213,25 @@
#include "my_struct_2_json.inc"
#include "my_struct_2_json.h"


#ifdef __cplusplus
extern "C" {
#endif
"""

void_main_header = r"""
#ifdef DEBUGS2J

int s2j_test(void)
{
#ifdef __cplusplus
S2jHook s2jHookCpp = {
.malloc_fn = ::operator new,
.free_fn = ::operator delete,
};

s2j_init(&s2jHookCpp);
#endif

char file_name[] = "struct_defination.json";
FILE *fp;

Expand Down Expand Up @@ -284,7 +310,7 @@
}
#endif /* end of __cplusplus */
"""
str_return = head_str + return_code + "#ifdef DEBUGS2J \n int s2j_test(void)\n" +" {\n\t" + void_main_header + str_s2j_test + str_s2j_test_tail + str_s2j_test2_header + str_s2j_test2 + void_main_tail
str_return = head_str + return_code + "\n\t" + void_main_header + str_s2j_test + str_s2j_test_tail + str_s2j_test2_header + str_s2j_test2 + void_main_tail
#print(str_return)

error_return = error_print_json2bin + "\n" + "*************************************" + "\n" + error_print_bin2json
Expand Down
32 changes: 13 additions & 19 deletions demo/inc/mc_usr_def.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,28 +16,22 @@ example
#include <string.h> /* define string handling functions */

#ifdef __cplusplus
extern "C" {
#include <string>
typedef struct CppStructInfoS
{
std::string string1;
std::string stringArray2[2];
bool b1;
bool bArray2[2];
wchar_t wc1;
wchar_t wcArray[2];
} CppStructInfoT, *pCppStructInfoT;
#endif

#ifdef __cplusplus
extern "C" {
#endif

/*****************************************************************************
**
** Type Defination
**
*****************************************************************************/


/*****************************************************************************
**
** Macro
**
*****************************************************************************/

/******************************************************************************
**
** Structure
**
******************************************************************************/

typedef int int32;
typedef long long int64;
Expand Down
12 changes: 12 additions & 0 deletions demo/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,18 @@
#include <stdio.h>

#ifdef DEBUGS2J
#ifdef __cplusplus
extern "C" {
extern int s2j_test(void);
extern int s2j_test2(void);
}
#else
extern int s2j_test(void);
extern int s2j_test2(void);
#endif
#endif// DEBUGS2J

#ifndef __cplusplus
typedef struct {
char name[16];
} Hometown;
Expand Down Expand Up @@ -104,8 +112,10 @@ static cJSON *struct_to_json(void* struct_obj) {
/* return Student JSON object pointer */
return json_student;
}
#endif

int main(void) {
#ifndef __cplusplus
static Student orignal_student_obj = {
.id = 24,
.weight = 71.2,
Expand All @@ -128,6 +138,7 @@ int main(void) {

s2j_delete_json_obj(json_student);
s2j_delete_struct_obj(converted_student_obj);
#endif

#ifdef DEBUGS2J
s2j_test();
Expand All @@ -136,3 +147,4 @@ int main(void) {

return 0;
}

Loading