Git Product home page Git Product logo

struct2json's Introduction

C结构体与 JSON 快速互转库


struct2json

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

起源

把面向对象设计应用到C语言中,是当下很流行的设计**。由于C语言中没有类,所以一般使用结构体 struct 充当类,那么结构体变量就是对象。有了对象之后,很多时候需要考虑对象的序列化及反序列化问题。C语言不像很多高级语言拥有反射等机制,使得对象序列化及反序列化被原生的支持。

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

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

如何使用

声明结构体

如下声明了两个结构体,结构体 Hometown 是结构体 Student 的子结构体

/* 籍贯 */
typedef struct {
    char name[16];
} Hometown;

/* 学生 */
typedef struct {
    uint8_t id;
    uint8_t score[8];
    char name[10];
    double weight;
    Hometown hometown;
} Student;

将结构体对象序列化为 JSON 对象

使用前(源文件 使用后(源文件
结构体转JSON-使用前 结构体转JSON-使用后

将 JSON 对象反序列化为结构体对象

使用前(源文件 使用后(源文件
JSON转结构体-使用前 JSON转结构体-使用后

V2.0版本新增功能【yuxuebao】

1) 更新cJSON库至1.7.12版本,并扩充实现,支持int64 (long long)类型数据。PS:cJSON原来int64类型以double方式处理,如果超过16位会有精度损失。

2) 扩展struct2json功能,增加支持结构体内包含结构体成员,支持包含数组成员。

3) 增加struct2json 结构体与JSON转换代码自动生成的Python脚本,支持从头文件中提取结构体定义,并根据结构体定义自动生成结构体与JSON互转代码,并提供相关示例。

V2.0 使用说明:

1) 提取结构体定义:

	将头文件(eg:mc_usr_def.h)放在demo\inc目录下;
	执行generate_struct_defination.py,生成struct_defination.txt;

2) 生成结构体与JSON互转代码:

	执行generate_s2j_code.py,根据结构体定义自动生成结构体与JSON互转代码:my_struct_2_json.c,my_struct_2_json.h;
	该脚本支持的参数类型有 基本类型 和 结构体类型,enum和指针按int处理,不支持union和位域;
	支持的数组类型:支持基本类型一维数组,结构体一维数组,字符二维数组(字符串数组)

3) 测试结构体与JSON转换:

	cd demo
	编译测试代码,gcc ../cJSON/cJSON.c ../struct2json/src/*.c ./*.c -I ../cJSON/ -I ../struct2json/inc/ -lm -DDEBUGS2J  -g -o tests2j
	测试 ./tests2j 
	查看output输出和生成的JSON样例文件struct_defination.json;
	预期输出:*:strcmp:0     *:strcmp:0

*:json_cmp:1

欢迎大家 fork and pull request(Github|OSChina|Coding) 。如果觉得这个开源项目很赞,可以点击项目主页 右上角的Star,同时把它推荐给更多有需要的朋友。

文档

具体内容参考\docs\zh\下的文件。务必保证在 阅读文档 后再使用。

许可

  • Armink (original author)
  • Yu Xuebao (current maintainer)
  • and the other contributors (CONTRIBUTORS.md)

MIT Copyright (c) [email protected]

struct2json's People

Contributors

armink avatar jokidream avatar libradoge avatar yuxuebao avatar zbcfscc avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

struct2json's Issues

关于编译器warring

这个写法编译器会提示warring:
if (!(copy = (char*)cJSON_malloc(len))) return 0;

建议写成:
copy = (char*)cJSON_malloc(len);
if (!copy) return0;

error: redeclaration of ‘json_temp’ with no linkage cJSON *json_temp;

./src/struct2json-master/struct2json/inc/s2jdef.h:171:12: error: redeclaration of ‘json_temp’ with no linkage
cJSON *json_temp;
^
./src/struct2json-master/struct2json/inc/s2j.h:66:5: note: in expansion of macro ‘S2J_CREATE_STRUCT_OBJECT’
S2J_CREATE_STRUCT_OBJECT(struct_obj, type)
^
src/service.c:28:5: note: in expansion of macro ‘s2j_create_struct_obj’
s2j_create_struct_obj(data, QT_DATA);
^
./src/struct2json-master/struct2json/inc/s2jdef.h:171:12: note: previous declaration of ‘json_temp’ was here
cJSON *json_temp;
^
./src/struct2json-master/struct2json/inc/s2j.h:66:5: note: in expansion of macro ‘S2J_CREATE_STRUCT_OBJECT’
S2J_CREATE_STRUCT_OBJECT(struct_obj, type)
^
src/service.c:18:5: note: in expansion of macro ‘s2j_create_struct_obj’
s2j_create_struct_obj(base, BASE);

我没动过这代码啊。
是BUG吗?还是我没用对?

资源占用情况

可以把资源占用情况放到介绍里。

因为想把这个项目用在单片机上,但不清楚它对平台的要求和资源占用情况

整数转换的结果,打印显示 ld

我将 字符串 和 整数 转换成 json格式,然后用串口发送出去,字符串转换没问题,但整数转换得到的结果,用串口打印 %d 正常,用串口打印 %s 却显示 ld,不知道什么原因造成,而我需要发送的json数据,要能正常显示整数值。
请问如何解决
`

typedef struct
{
char TestString[10];
int TestInt;
}Struct_test;

cJSON struct_to_json_Struct_test(void struct_obj)
{
s2j_create_json_obj(json_obj_);
Struct_test *struct_obj_ = (Struct_test *)struct_obj;
s2j_json_set_basic_element(json_obj_, struct_obj_, string, TestString);
s2j_json_set_basic_element(json_obj_, struct_obj_, int, TestInt);
return json_obj_;
}

void json_to_struct_Struct_test(cJSON json_obj)
{
s2j_create_struct_obj(struct_obj_, Struct_test);
s2j_struct_get_basic_element(struct_obj_,json_obj, string, TestString);
s2j_struct_get_basic_element(struct_obj_,json_obj, int, TestInt);
return struct_obj_;
}

int main(void)
{
static Struct_test _Struct_test =
{
.TestString = "OK",
.TestInt = 123
};

cJSON *p1 = struct_to_json_Struct_test(&_Struct_test);
if(p1 != NULL)
{
	char *p2 = cJSON_Print(p1);
	if(p2 != NULL)
	{
		UartPrint("\nThe Json is:\n%s",p2);

		Struct_test *converted_obj = json_to_struct_Struct_test(p1);

		if (memcmp(&_Struct_test, converted_obj, sizeof(Struct_test)))
		{
			UartPrint("\nConverted failed!\n");
		}
		else
		{
			UartPrint("\nConverted OK!\n");

			UartPrint("converted_obj->TestString = %s\n", converted_obj->TestString);
			UartPrint("converted_obj->TestInt = %d\n", converted_obj->TestInt);
		}			
	}
}

return 0;

} `

运行结果:
The Json is:
{
"TestString": "OK",
"TestInt": ld
}
Converted OK!
converted_obj->TestString = OK
converted_obj->TestInt = 123

保存json数据到文件

你好,我看到示例代码中好像没有保存转换后的json数据到文件的操作,我想知道是没有提供这个接口吗?还是说只是样例中没有实现这一部分?
谢谢了!

用 clang 提取头文件中的结构体定义信息

增加struct2json 结构体与JSON转换代码自动生成的Python脚本,支持从头文件中提取结构体定义,并根据结构体定义自动生成结构体与JSON互转代码,并提供相关示例。

我看这个好像是使用正则表达式完成的信息提取? 我最近也碰到了类似的需求,但是是用 clang 生成 btf 信息之后实现代码生成的;

https://github.com/eunomia-bpf/c-struct-bindgen

有没有想过使用 clang 导出 ast 和 debug 信息,或者 btf 信息,来做这样的事情? (btf 也可以理解成 debug 信息的一种,通过 clang -target bpf -g 即可生成,可以用 libbpf 解析获取结构体定义,类型和字段之类的)

结构体的成员是 结构体数组 如何转换

/* 兴趣 */

举个例子,如 一个学生有多个兴趣, 兴趣也是一个结构体。这种场景如何转换。

typedef struct {
char name;
int rank;
} Interest

/* 籍贯 */
typedef struct {
char name[16];
} Hometown;

/* 学生 */
typedef struct {
uint8_t id;
uint8_t score[8];
char name[10];
double weight;
Hometown hometown;
Interest interest[10]
} Student;

An unsafe operation is found in the S2J_STRUCT_GET_string_ELEMENT function

struct2json

Vulnerability Analysis

An unsafe operation is found in the S2J_STRUCT_GET_string_ELEMENTfunction. The strcpy function is used to copy JSON->value to the struct, which may cause overflow when JSON->value is longer than structure defined array size.

img

POC

#include "s2j.h" 
#include <stdint.h> 
#include <stdio.h> 
 
typedef struct { 
  char name[8]; 
} Hometown; 
 
static void *json_to_struct(cJSON* json_obj) { 
  /* create Hometown structure object */ 
  s2j_create_struct_obj(struct_hometown, Hometown); 
 
  /* deserialize data to Hometown structure object. */ 
  s2j_struct_get_basic_element(struct_hometown, json_obj,string, name); 
  return struct_hometown; 
} 
 
 
int main(void) { 
  cJSON * json=NULL; 
 
  json=cJSON_CreateObject(); 
 
  cJSON_AddStringToObject(json, "name", "ABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZABCDEFGHIJKLMNOPQRSTUVWXYZ"); 
   
  Hometown * test=json_to_struct(json); 
 
  printf("that\'s fine!%zu",sizeof(test)); 
 
 
  return 0; 
}

Run:

img

Suggestion

Use strncpy instead of strcpy to control the length of JSON->value

#define S2J_STRUCT_GET_string_ELEMENT(to_struct, from_json, _element) \ 
  json_temp = cJSON_GetObjectItem(from_json, #_element); \ 
  if (json_temp) strncpy((to_struct)->_element, json_temp->valuestring,sizeof((to_struct)->_element));

After modification:

img

cJSON_Print 返回的指针地址为NULL

经实际使用于STM32F107中,cJSON_Print 返回的指针地址为NULL,请问这个是什么原因?

代码如下:
static Student orignal_student_obj = {
.id = 24,
.weight = 71.2,
.score = {1, 2, 3, 4, 5, 6, 7, 8},
.name = "armink",
.hometown.name = "China",
};

cJSON *json_send = struct_to_json(&orignal_student_obj);

//cJSON *json_send = struct_to_json(&send_struct);

ptr = cJSON_Print(json_send);

strncpy length?

struct2json\inc\s2jdef.h line93
strncpy((to_struct)->_element[index], from_json->valuestring,sizeof((to_struct)->_element)-1);
是不是应该是
strncpy((to_struct)->_element[index], from_json->valuestring,sizeof((to_struct)->_element[index])-1);
struct2json\inc\s2jdef.h line106 同样问题.

结构体中存在枚举类型如何处理

结构体中存在枚举类型,生成代码运行后,存在如下问题,
my_struct_2_json.c:(.text+0xad9): undefined reference to struct_to_json_E_DATA_TYPE' /tmp/cc600xmd.o: In function json_to_struct_app_data':
my_struct_2_json.c:(.text+0xbe4): undefined reference to json_to_struct_E_DATA_TYPE' /tmp/cc600xmd.o: In function struct_to_json_sync_data':
my_struct_2_json.c:(.text+0xc97): undefined reference to struct_to_json_E_DATA_TYPE' /tmp/cc600xmd.o: In function json_to_struct_sync_data':
my_struct_2_json.c:(.text+0xda2): undefined reference to `json_to_struct_E_DATA_TYPE'
E_DATA_TYPE是一个枚举类型, 请问这种情况有解决方案吗

create缺少对应的delete方法

s2j_create_json_obj和s2j_create_struct_obj接口没有对应的delete方法。

s2j_create_json_obj可以用cJSON_Delete去删除,但是使用上有点混乱,建议增加一个s2j_delete_json_obj.

s2j_create_struct_obj中可以使用自定义的malloc_fn函数,如果没有对应的s2j_delete_struct_obj,那么s2j_init中传入的free_fn就没有起到作用。

示例的main.c文件,退出前没有释放申请的obj,建议增加释放操作。

关于结构体数组的嵌套

目前struct2json的json数组只支持int、string、double等基本类型。但不支持数组嵌套json类,所以不能对嵌套了“结构体数组”的结构体进行转换。能否考虑增加json数组对json类的嵌套,以适用于更加灵活的结构体类型。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.