参考 protobuf 的想法,写了个 C 语言的 JSON 处理库,可以方便完成 C struct 到 JSON 之间的转换 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
爱意满满的作品展示区。
liaotonglang
V2EX    分享创造

参考 protobuf 的想法,写了个 C 语言的 JSON 处理库,可以方便完成 C struct 到 JSON 之间的转换

  •  
  •   liaotonglang 2022-03-24 16:46:16 +08:00 3080 次点击
    这是一个创建于 1301 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近用 C 语言处理 JSON ,感觉很麻烦,就写了这个可以生成 JSON 处理代码的程序。

    https://github.com/zltl/json-gen-c

    cover

    json-gen-c 通过读取结构体 (struct) 定义文件,生成对应的 JSON 处理代码。这些代码包括 struct 结构体定义,结构体初始化和清理函数,结构体 JSON 编码和解码函数。

    编译

    使用下列命令构建并安装:

    make sudo make install 

    使用示范

    1. 编辑 struct.json-gen-c 文件,内容如下
    // 结构体定义文件 // 定义结构体 A struct A { // 定义成员变量 int int_val1; int int_val2; long long_val; double double_val; float float_val; sstr_t sstr_val; // 还可以定义数组 int int_val_array[]; // 定义别的结构体类型的变量 B b_val; }; // 定义结构体 B struct B { int id; }; 
    1. 构建 json.gen.cjson.gen.h

    使用下列命令创建 json 处理代码:

    json-gen-c -in struct.json-gen-c -out . 

    命令创建了 json.gen.cjson.gen.h 文件,其中包含了 json 处理代码。同时创建了他们依赖的 sstr.hsstr.c,这是用于字符串处理的代码,程序中大量地方使用了他们。

    1. 使用 json 处理代码 例如要解析 JSON 字符串到结构体 A
    // const char *p_str = "{this is a json string}"; // sstr_t json_str = sstr(pstr); struct A a; A_init(&a); json_unmarshal_A(json_str, &a); // 注意 json_str 是 sstr_t 类型的 // ... A_clear(&a); 

    要解析 JSON 字符串到结构体 A 的数组 A a[]:

    // const char *p_str = "this is a json string"; // sstr_t json_str = sstr(pstr); struct A *a = NULL; int len = 0; json_unmarshal_array_A(&a, &len, json_str); // 注意 json_str 是 sstr_t 类型的 // ... int i; for (i = 0; i < len; ++i) { A_clear(&a[i]); } free(a); 

    要将结构体 A 序列化成 JSON 字符串:

    struct A a; A_init(&a); // set values to a ... // ... sstr_t json_str = sstr_new(); json_marshal_A(&a, json_str); printf("marshal a to json> %s\n", sstr_cstr(json_str)); sstr_free(json_str); A_clear(&a); 

    要将结构体数组 A a[] 序列化成 JSON 字符串:

    struct A a[3]; for (i = 0; i < 3; ++i) { A_init(&a[i]); // set values to a[i] ... } sstr_t json_str = sstr_new(); json_marshal_array_A(a, 3, json_str); printf("marshal a[] to json> %s\n", sstr_cstr(json_str)); for (i = 0; i < 3; ++i) { A_clear(&a[i]); } 

    结构定义文件格式

    结构定义格式如下:

    struct <struct_name> { <field_type> <field_name> []?; <field_type> <field_name> []?; ... }; 

    <field_type> 可以是下列内容之一:

    • int
    • long
    • float
    • double
    • sstr_t
    • a struct name

    如果是成员变量是一个数组,就在变量名后面加 []。name.

    API

    // initialize a struct // always return 0 int <struct_name>_init(struct <struct_name> *obj); // uninitialize a struct // always return 0 int <struct_name>_clear(struct <struct_name> *obj); // marshal a struct to json string. // return 0 if success. int json_marshal_<struct_name>(struct <struct_name>*obj, sstr_t out); // marshal an array of struct to json string. // return 0 if success. int json_marshal_array<struct_name>(struct <struct_name>*obj, int len, sstr_t out); // unmarshal a json string to a struct. // return 0 if success. int json_unmarshal_<struct_name>(sstr_t in, struct <struct_name>*obj); // unmarshal a json string to array of struct // return 0 if success. int json_unmarshal_<struct_name>(sstr_t in, struct <struct_name>**obj, int *len); 
    10 条回复    2022-03-24 22:10:31 +08:00
    0o0O0o0O0o
        1
    0o0O0o0O0o  
       2022-03-24 17:01:25 +08:00 via iPhone
    https://app.quicktype.io/

    更习惯这种依据 json 生成定义和代码的流程
    darkbfly666
        2
    darkbfly666  
       2022-03-24 17:10:48 +08:00
    darkbfly666
        3
    darkbfly666  
       2022-03-24 17:11:27 +08:00
    我也再这里推荐一下 这个库 挺好用的
    3dwelcome
        4
    3dwelcome  
       2022-03-24 17:13:22 +08:00
    json 是可变类型,怎么能把结构写死呢。

    正常都是把 json 转换成一些可变对象,比如 C++里面的 VARTYPE 对象,一个类型包含了 20 个子类型。

    然后根据 json key 再解析具体数据,结构写死一点容错性都没有了。json 毕竟不是 proto ,不可能保证 100%结构正确的。
    liaotonglang
        5
    liaotonglang  
    OP
       2022-03-24 17:14:51 +08:00
    @0o0O0o0O0o quicktype 确实方便啊,要是他有纯 C 的版本,我也不至于那么累。有空的话我给他加一个纯 C 语言依赖 cJSON 的选项。
    3dwelcome
        6
    3dwelcome  
       2022-03-24 17:17:06 +08:00
    举个例子,json 节点下有一堆 array ,有时候为空,有时候为 A 结构,有时候为 B 结构。

    具体类型最终是服务器来确定,你这样变成了客户端来确定结构了。
    liaotonglang
        7
    liaotonglang  
    OP
       2022-03-24 17:20:56 +08:00
    @3dwelcome 只是提供一个选项,强类型的 json 处理也有一定的使用场景。比如 golang 的 encoding/json 包,或者 rust 的 serde_json ,他们都提供了强类型的选项,同时支持将 json 解码为无类型结构。
    liaotonglang
        8
    liaotonglang  
    OP
       2022-03-24 17:21:37 +08:00
    @3dwelcome 可惜在 C 语言里,我没找到与他们相对应的方便的语法,就只有强类型结构了
    liaotonglang
        9
    liaotonglang  
    OP
       2022-03-24 17:25:17 +08:00
    @darkbfly666 xpack 看起来很方便,但语法看起来挺奇怪的,我怕会引起同事们反复的提问。如果做 C++的项目我还是会用 nlohmann::json 或者直接用 @0o0O0o0O0o 提到的 quicktype 。
    gyf304
        10
    gyf304  
       2022-03-24 22:10:31 +08:00 via iPhone
    写过个类似的 https://v2ex.com/t/753390
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     2941 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 26ms UTC 12:50 PVG 20:50 LAX 05:50 JFK 08:50
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86