免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
楼主: lxyscls
打印 上一主题 下一主题

[C] 请问如何通过结构体的基地址和偏移来操作其成员变量? [复制链接]

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
21 [报告]
发表于 2011-11-19 22:44 |只看该作者
本帖最后由 yulihua49 于 2011-11-19 22:50 编辑
yulihua49 发表于 2011-11-19 22:40



    把结构改一下,a改为short,看看模板里的offset:
它会按照编译器的规则计算offset,不需要也不允许做#pragma pack
  1. cat xx.c
  2. #include <pack.h>
  3. #include <json_pack.h>

  4. T_PkgType xx_tpl[]={
  5.         {CH_SHORT,sizeof(short),"a",NULL,-1},
  6.         {CH_CLOB,-1,"b"},
  7.         {CH_CLOB,-1,"c"},
  8.         {-1,0,"xx",0}
  9. };

  10. typedef struct {
  11.         short a;
  12.         char *b;
  13.         char *c;
  14. } xx_stu;

  15. int main()
  16. {
  17. xx_stu xx;
  18. JSON_OBJECT json=json_object_new_object();
  19. T_PkgType *tp;

  20.         xx.a=1234;
  21.         xx.b="abcd";
  22.         xx.c="ABCD";

  23.         struct_to_json(json,&xx,xx_tpl,NULL);
  24.         printf("xx:%s\n",
  25.                 json_object_to_json_string(json));
  26.         json_object_put(json);
  27.         for(tp=xx_tpl;tp->type>-1;tp++)
  28.                 printf("%s offset=%d,",tp->name,tp->offset);
  29.         printf("\nsizeof xx=%d\n",tp->offset);
  30.         return 0;
  31. }
  32. tjs@linux:~/src> make
  33. cc -I/workspace/project/ticket-query/02-src/train-lines/sdbc/include   -c -o xx.o xx.c
  34. cc -o xx xx.o -L/workspace/project/ticket-query/02-src/train-lines/sdbc/lib -lstr -ljson -lm -lpthread
  35. tjs@linux:~/src> ./xx
  36. xx:{ "a": "1234", "b": "abcd", "c": "ABCD" }
  37. a offset=0,b offset=4,c offset=8,
  38. sizeof xx=12
复制代码

论坛徽章:
0
22 [报告]
发表于 2011-11-20 00:12 |只看该作者
本帖最后由 keytounix 于 2011-11-20 00:31 编辑

回复 19# yulihua49

佩服!

你这个方法确实很巧!

也很好!

看完后我 有点启发

你是通过构造一个模版

但是还是需要通过一个"模版"

既然这样,

为什么不在结构体本身下功夫?

LZ的结构体信息
typedef struct {

        short a;

        char *b;

        char *c;

} xx_stu_t;

#define short_t 1
#define char_p_t 2
.....
现在我们构建一个新的结构体
#define JSON_STRUCT_FLAG "json"
typedef JSON_STRUCT
{
char * json_struct_FLAG;
char * seg_size;//用动态内存依次存放xx_stu_t中的数据类型;
char * seg_name;用动态内存molloc依次存放xxx_stu中的段名称
xx_stu_t stu;
} J_xx_stu_t;

比如LZ的结构体信息
可以打包成JSONstruct他、如下

J_xx_stu_t j_stu;


j_stu.json_struct_FLAG<-  JSON_STRUCT_FLAG



j_stu.seg_size=malloc(10);

j_stu.seg_size[0]=short_t;
j_stu.seg_size[1]=char_p_t;
j_stu.seg_size[2]=char_p_t;

j_stu.seg_name<- "a,b,c"


struct_to_json(JSON * json,void * json_struct);

这个相比你那个来说有一个优点就是
模版都不要了
也就是说适合所有的按照JSON_STRUCT 结构这种格式封装的结构体
你那个只适合按照你那个模版构造的结构体
但是缺点也是很明显的
就是
1.
json_struct这个东西封装了 数据类型和 结构体成员名称,
这个增加了额外的额外的空间,
如果处理大批量数据,
这个就有点悬了

2.
存在偏移量计算的问题,
因为编译器优化的时候,
可能会把结构体打乱,
__attribute__(pakged)能处理这个问题?

你的那个是否也会存在这个问题?

论坛徽章:
0
23 [报告]
发表于 2011-11-20 00:40 |只看该作者
本帖最后由 keytounix 于 2011-11-20 09:11 编辑

回复 21# yulihua49


    写了上面这个,我又想起另外一种方式,这个是我觉得最安全最可靠的
想的有点仓促,写出来可能会有很多错误,欢迎指正


typedef struct {

        short no;

        char *name;

        char * class;

} xx_stu_t;

xx_stu_t stu_t{100,"li4","class 4"}
这个结构体改造

typedef struct {

int32 num_of_seg;//存放字段的总数      
char * *seg_1;//不管他叫什么名称,反正我们在调用他时不需要,只需要偏移量

............

} J_stu_t __attribute__(pakged);


在a.c中
初始化LZ这个结构体如下


J_stu_t j_stu;
j_stu.num=3;

*j_stu.name<---"name:li4"
*j_stu.class<---"class:class 4"
......

注意这个
因为都是char **类型和
int32型
那么数据将是很对齐的东西

这意味着在这个结构体 存储的东西将是如下结构
&jst地址开始信息如下
&jst:        3
&jst+4:   addr1
&jst+8:   addr2
&jst+12:  addr3


---------------
addr1:  "no,100"
addr2:  "name,li4"
addr3:  "class,class 4"

这样岂不是很好?

在b.c中,我们不需要知道J_STU_t的具体内容
只需要知道一个事实就是


J_STU_t第一个4字节单元存放的是元素的个数
以后的都是指针


在struct_to_json()函数中

int struct_to_json(JSON * json,J_STU_t * jst)
{
int num;
memcpy(&num,jst,4)
//这个就获得了元素的数目
#define N 100
char buf[N]


#define  get_seg(seg_index,buf) \
do{                                              \
      memset(buf,0x00,N);            \
      memcpy(buf,*(jst + seg_index* 4),strlen(*(jst + seg_index* 4));\
}while(0);

}

for i<-  [1,num]
get_seg(i,buf);
func(json,buf);
end for

}

如此不是很好吗?



这个 方法的优点很明显

就是不会出现因为编译器优化造成的偏移量 计算错误的问题

为什么?
因为都是以4字节递增的
int  char ** 都是4字节
这个是非常安全的,
编译器优化或者不优化,都不会出现问题

另外缺点
可能体现在内存上

首先,结构体的开销可能不变
为什么?
虽然结构体中增加了一个int变量,
但是考虑到对齐问题,这个可能是一样的

当然上面给出的结构体 是不能体现这个结论的

其次,存储字段存放的额外开销
也就是每个字段 增加了  strlen(seg_name)+ 1个冒号这个开销
粗略估算 大概每一个字段增加9+1=10个字节左右


这些是需要考虑的

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
24 [报告]
发表于 2011-11-21 12:29 |只看该作者
本帖最后由 yulihua49 于 2011-11-21 12:51 编辑
回复  yulihua49

2.
存在偏移量计算的问题,
因为编译器优化的时候,
可能会把结构体打乱,
__attribute__(pakged)能处理这个问题?

你的那个是否也会存在这个问题?keytounix 发表于 2011-11-20 00:12


结构布局不允许优化,也不允许pack。
十几年来,在很多应用环境和测试环境使用,没有发现哪个编译器优化布局。

看看你的方案,也很有意思,你不妨试试。
你这个可以叫“混合模板”方式,把模板和数据放在一起。这与C++反射技术类似,有人做了C++反射类,就像JAVA一样,能够找到对象里的变量、值、属性,可以序列化和反序列化。

不过还得探讨一下:
每个数据增加的空间不是问题。有时在数据库里,许多表同构,我用一个模板就可以了。
在多个模块中,模板可以共享,偏移量计算一次就可以了,在多线程中也是。

处理批量数据,我用一个结构数组就可以了,容易组织。
还有,很多时候只需要模板而不需要显式的结构,就是隐式结构。

如果人家已经定义了许多结构,你给配模板就行了,不用大规模修改原软件。
最后,我的模板可以通过数据库的表结构自动生成,可以用元数据库生成结构和模板。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
25 [报告]
发表于 2011-11-21 12:40 |只看该作者
本帖最后由 yulihua49 于 2011-11-21 15:55 编辑
回复  yulihua49

int num;
memcpy(&num,jst,4)
keytounix 发表于 2011-11-20 00:40


int num;
memcpy(&num,jst,4)
这个可不行。不过你的意思我明白。

数据里所有成员都用指针,管理起来太复杂。好像JSON对象也是这么做的,见json-c-0.9。
你要写很多函数协助工作,如按名存取数据(bean),按索引存取数据等等。那些内存如何管理?不要违例或泄漏了。
还不如用protobuf呢,属于特定对象一类。
坛子里有一哥们要做protobuf的ORM呢。这可能超出了楼主的需求,但是符合更一般的需求。

为了解决数据集合在运行时解析(运行时访问其内容)的问题,大家真是想了不少办法,但是面对原生态的结构的办法不多。

我的独立模板面对的是普通的原生态的结构,也是要进行SRM(Struct Relational Mapping)的,就像JAVA的Hibernate一样。

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
26 [报告]
发表于 2011-12-05 21:47 |只看该作者
回复  yulihua49


    写了上面这个,我又想起另外一种方式,这个是我觉得最安全最可靠的
想的有点仓 ...
keytounix 发表于 2011-11-20 00:40


http://space.itpub.net/8804348/viewspace-478471#xspace-itemreply

论坛徽章:
0
27 [报告]
发表于 2011-12-06 16:42 |只看该作者
回复 26# yulihua49


    一旦扯上数据库就有点晕乎
  我打过交道的只有sqlite

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
28 [报告]
发表于 2011-12-07 16:09 |只看该作者
本帖最后由 yulihua49 于 2011-12-07 16:41 编辑
回复  yulihua49


    一旦扯上数据库就有点晕乎
  我打过交道的只有sqlite
keytounix 发表于 2011-12-06 16:42



    也没什么。
就是数据库里有表,表结构与C结构可以有一个对应关系。扩展到多表,或一个复杂的SQL语句,也能找到与之对应的C结构。
寻找对应的结构比较复杂,但是之后有了结构和模板,处理起来就简单了。
用我的办法比较简单,你的办法就困难一些。
比如:ORACLE
  1. drop table UNIKEY_TEST ;
  2. create table UNIKEY_TEST (
  3.         ID              number(8)       not null,       --存款ID,包括币种,类别,存期等等
  4.         BEG_DATE        date            not null,       -- 开始日期
  5.         RATE            number(8,2),                    --利率
  6.         FLAG            number(1),                      -- 0:可用,-1:不可用
  7.         NOTE            varchar2(120)                   -- 备注
  8. );
  9. create unique index idex on UNIKEY_TEST(ID,BEG_DATE desc);
复制代码
> mkpatt.sh
输入表名: UNIKEY_TEST

T_PkgType UNIKEY_TEST_tpl[]={
        {CH_INT,sizeof(int),"id",0,-1},
        {CH_JUL,sizeof(INT4),"beg_date",YEAR_TO_DAY},
        {CH_DOUBLE,sizeof(double),"rate","%10.2lf"},
        {CH_TINY,1,"flag"},
        {CH_CHAR,121,"note"},
        {-1,0,"UNIKEY_TEST","id|beg_date|"}          //表名和主键
};

extern T_PkgType UNIKEY_TEST_tpl[];
typedef struct {
        int id;
        INT4 beg_date;
        double rate;
        char flag;
        char note[121];
} UNIKEY_TEST_stu;

你看看那个模板,是不是很容易构建select语句?

SELECT 提取各列名 FROM 提取表名 WHERE 由主键构建主键表达式 
prepare之
然后绑定变量到结构,每个列的绑定位置就是结构的基地址+模板的偏移量。
Fetch一下,数据库里的数据就跑到结构里去了。

论坛徽章:
0
29 [报告]
发表于 2011-12-07 16:31 |只看该作者
本帖最后由 keytounix 于 2011-12-07 16:33 编辑

回复 28# yulihua49


    我认真看了你给的那个连接

   数据库里面大批量的数据操作

  采用你的这个 模版方法 大概是最好的了, 最利于维护的了

  我那个方法还是没有跳出C的局限

  也许认真学习一下数据库和java对开拓视野有很大的好处

论坛徽章:
15
射手座
日期:2014-11-29 19:22:4915-16赛季CBA联赛之青岛
日期:2017-11-17 13:20:09黑曼巴
日期:2017-07-13 19:13:4715-16赛季CBA联赛之四川
日期:2017-02-07 21:08:572015年亚冠纪念徽章
日期:2015-11-06 12:31:58每日论坛发贴之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-08-04 06:20:00程序设计版块每日发帖之星
日期:2015-07-12 22:20:002015亚冠之浦和红钻
日期:2015-07-08 10:10:132015亚冠之大阪钢巴
日期:2015-06-29 11:21:122015亚冠之广州恒大
日期:2015-05-22 21:55:412015年亚洲杯之伊朗
日期:2015-04-10 16:28:25
30 [报告]
发表于 2011-12-07 16:37 |只看该作者
本帖最后由 yulihua49 于 2011-12-07 16:44 编辑
回复  yulihua49


    我认真看了你给的那个连接

   数据库里面大批量的数据操作

  采用你的这个 ...
keytounix 发表于 2011-12-07 16:31



    用了很多年了,现在有很大的改进,弄的和Hibernate差不多了。

咱们没走题吧?

映射程序都是用结构的基地址+模板里的偏移量,根据类型和格式处理数据。

最新的程序可以在QQ群 SDBC的群共享下载,源码和文档。
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP