- 主题:如何写一个函数能够序列化任意结构
我这个没有预编译。
先看一个结构:
extern T_PkgType st_tpl[];
typedef struct {
char c;
INT64 bi;
} st_stu;
extern T_PkgType ss_tpl[];
typedef struct {
char c;
st_stu s;
int i;
} ss_stu;
这两个都是普通的结构体,第二个是结构套结构。
这是一个.h,include到文件里即可。
【 在 hgoldfish 的大作中提到: 】
: 感觉可以啊。 c 语言是比较简单的,纯为这个目的写个这种解析器听起来并不难。github 上面看到一些 c 语言解析器的开源代码库或者 libclang 拿起来开干。唯一的麻烦是增加预编译步骤很多人不喜欢。
:
--
修改:ylh0315 FROM 221.221.50.*
FROM 221.221.50.*
【 在 ylh0315 的大作中提到: 】
: 我这个没有预编译。
: 先看一个结构:
:
: ...................
现在给它配模板:
T_PkgType st_tpl[]={
{CH_TINY,1,"c",0,-1},
{CH_INT64,sizeof(INT64),"bi"},
{-1,0,0,0}
};
T_PkgType ss_tpl[]={
{CH_TINY,1,"c",0,-1},
{CH_STRUCT,0,"s",(const char *)st_tpl},
{CH_INT,sizeof(int),"i"},
{-1,0,0,0}
};
这是一个.c,include到任何一个.c或.cpp里即可。
--
FROM 221.221.50.*
//这个就是所谓的“模板”了,它使我们能够"看"到未知结构的内容。
typedef struct {
INT4 type;
INT4 len; // in byte
const char *name;
const char *format;
INT4 offset;
int bindtype; //default=0
} T_PkgType;
模板结构定义,每个成员一套,多个成员按次序组成数组。所有成员最后加一个尾标,type=-1;相当于尾零。
看楼上都有这么一行: {-1,0,0,0}
注意那个offset,就是成员相对于结构头的偏移量。写模板时不需要写。
第一个成员的offset写-1,这个是必须的。
第一次被使用时,程序发现这个是-1,就自动计算每个成员的offset,这一步就是倒推结构布局。计算结果,第一个成员的offset必定是0;这个就保证了计算只发生一次,这个系统的运行效率是非常高的。
【 在 ylh0315 的大作中提到: 】
: 现在给它配模板:
: T_PkgType st_tpl[]={
: {CH_TINY,1,"c",0,-1},
: ...................
--
修改:ylh0315 FROM 221.221.50.*
FROM 221.221.50.*
【 在 ylh0315 的大作中提到: 】
: //这个就是所谓的“模板”了,它使我们能够"看"到未知结构的内容。
: typedef struct {
: INT4 type;
: ...................
看看程序是怎样的:
JSON_OBJECT stu_to_json(JSON_OBJECT json,void *data,T_PkgType * typ,const char *choose,char *colidx)
{
int i,colnum,n;
T_PkgType *tp;
char buf[100];
const char *cp;
if(!json) return json;
colnum=set_offset(typ);//第一个offset是-1,就计算,否则直接返回。
tp=typ;
if(!choose||!*choose) { // 没有选择,全部加入
for(i=0;tp->type>=0;i++,tp++) {
if(tp->bindtype & NOSELECT) continue;//如果select不要这个,序列化也不要。
if(choose&&isnull((char *)data+tp->offset,tp->type)) continue;
if(tp->type==CH_STRUCT) {
JSON_OBJECT sub=json_object_new_object();
stu_to_json(sub,(char *)data+tp->offset,
(T_PkgType *)tp->format,0,0);
json_object_object_add(json,plain_name(tp->name),sub);
continue;
}
add_field_to_object(json,data,tp);
}
return json;
}
这个函数比我前边给的多了几个参数,不要紧,前三个一样,后边写0即可。
--
修改:ylh0315 FROM 221.221.50.*
FROM 221.221.50.*
应用场景:
从数据库得到一些“行”,或者叫做“rows”。放到结构里。然后序列化,返回到前端。
前端提出需要取数的表名和检索条件,先用模板生成SQL语句,经过数据库操作,把结果集反序列化到结构。
【 在 ylh0315 的大作中提到: 】
: 看看程序是怎样的:
: JSON_OBJECT stu_to_json(JSON_OBJECT json,void *data,T_PkgType * typ,const char *choose,char *colidx)
: {
: ...................
--
修改:ylh0315 FROM 221.221.50.*
FROM 221.221.50.*
C/C++,我实现过这种功能,最终是一个函数,参数需要结构体指针,结构体类型名还有一个你不知道的参数--结构体被使用的源代码文件名。
1,程序外围脚本,编译系统需要配合修改。为了性能,先编译,生成一个小exe,使用-g3模式编译,保留内部DWARF信息,小exe用来提取dwarf信息,重建结构体结构信息使用;
2,下载dwarfdump源代码,魔改!!使之能从exe中读取TAG, ATTR。建立状态机跟踪结构体,字段的解析状态。DWARF里的结构体信息保存是不会嵌套的,子类型直接用子类型的16进制tag做索引;
a,实现一个读取小exe,解析结构体类型树的函数生成类型树的功能;多次循环解析exe中的dwarf,直到待求解结构体类型的所有子类型都被解析或者某次解析未能识别出任何有用tag
b,实现一个使用类型树对结构体指针内存进行反向解析输出的功能
(第二部,我做了一个月才能用,领导看我的眼神都变了,他们不喜欢这种深耕类型的技术)
--
修改:pfan117 FROM 59.109.156.*
FROM 59.109.156.*
序列化,反序列化有没有人实现过这这个功能:
对于struct A,序列化后会生成一个极其长的byte stream,比如1TBytes大小。
然后把这个1T写入存储。
反序列化的时候是:void deserialize(void *buf, size_t length, struct A &dst);
需要先读出这个1T大小的buffer,然后调用deserialize()函数恢复dst。
有时候1T太大了,如果能“分段反序列化”:
cursor_type cursor;
while(!cursor.done()){
auto [buf, len] = read_1_MByte_from("saved_1T_file", 1MB);
cursor = deserialize(buf, len, dst, cursor);
}
引入一个cursor变量,每次从文件读出一部分,反序列化struct A中的一部分,循环直到显示cursor已经被全部序列化完毕。
序列化时候也一样,每次从struct A中序列化一部分,压缩/存储,然后序列化下一部分,压缩/存储。
通过cursor的形式,把任何支持serialize/deserialize的struct都变成一个带cursor的byte stream view,岂不美哉。
--
修改:allegro FROM 158.140.1.*
FROM 158.140.1.*
你这不算啊
【 在 ylh0315 的大作中提到: 】
: 但是我做到了,利用映射机制,就是写一个结构说明书。
: 这办法对于已经存在的第三方软件的已知结构也适用,给它写个说明书。就是template。
--
FROM 114.249.23.*
算不算,反正解决问题。
做了一套SRM系统,可以高效率的访问数据库。
实现柔性编程,一个功能模块,可以处理好几个表。
【 在 littleSram 的大作中提到: 】
: 你这不算啊
--
FROM 221.221.50.*
23楼的程序,就是可以处理任意结构呀。
【 在 littleSram 的大作中提到: 】
: 你这不算啊
--
FROM 221.221.50.*