Chinaunix

标题: 结构体的问题,欢迎指点 [打印本页]

作者: bosi_cat    时间: 2008-07-08 12:32
标题: 结构体的问题,欢迎指点
有没有人玩过这样的问题:有一个结构体,动态的取一个成员变量的值,怎么实现?
比如:
struct aaa { int a ; int b } bbb;

char name[4];
strcpy( name, "b" );

怎么获取到name这个变量指定的成员的值?
作者: jamesr    时间: 2008-07-08 12:34
提示: 作者被禁止或删除 内容自动屏蔽
作者: langue    时间: 2008-07-08 12:39
你是想说associative arrays?抱歉,C做不到,你可以看看PHP和Perl。
作者: system888net    时间: 2008-07-08 12:41
原帖由 bosi_cat 于 2008-7-8 12:32 发表
有没有人玩过这样的问题:有一个结构体,动态的取一个成员变量的值,怎么实现?
比如:
struct aaa { int a ; int b } bbb;

char name[4];
strcpy( name, "b" );

怎么获取到name这个变量指定的成员的值?


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

[ 本帖最后由 system888net 于 2008-7-8 12:59 编辑 ]
作者: mingyanguo    时间: 2008-07-08 12:49
没猜错你的意思的话,大概可以这么写,

  1. struct {
  2.     const char *fieldname;
  3.     unsigned long fieldoff;
  4. } offsets[] = {
  5. #define    OFFSETNAME(x)    { .fieldname = #x, .fieldoff = offsetof(struct aaa, x), }
  6. #define    ENDOFFSETNAME   { .fieldname = NULL, }
  7.     OFFSETNAME(a),
  8.     OFFSETNAME(b),
  9.     ENDOFFSETNAME
  10. };


复制代码

然后可以根据name找到其offset,然后通过类型强制转换来读name对应的field。

--代码随手写的,仅达意,未必能编译
作者: shan_ghost    时间: 2008-07-08 13:57
我做过。

需求是:
    1、将预定义的c结构体写成固定格式的xml字符流,或从xml字符流中恢复此c结构体。
    2、此类操作逻辑相对固定,能否写成通用函数?


思路:
1、使用offsetof宏求得c结构体中每个字段相对于指向该结构体的指针的偏移。

例:
struct aa
{
  int I1; //offsetof(aa,I1) = 0
  int I2; //offsetof(aa,I2) = 4
}

若 aa * point = &x, 则 *(int *)((void *) point + offsetof(aa,I1))就相当于point->I1


2、生成一个全局对应表,记录struct名、成员变量偏移、成员变量数据类型以及它们对应的字符串名称(如"aa"、"I1"、"I2"等)
我当时定义了一组宏,很简单就可完成这个工作。

3、没啥了。查表、转换而已(如 输入“aa->I1 = 2”或"<aa><I1>2</I1></aa>",就将其转换为 aa a1; *(int *)((void*)&a1 + offsetof(aa,I1)) = 2)。
这里也可以定义成宏。



注意: 这是我当时在c中实现的方法,非常丑陋;c++中提供有更好的方法(请 google 搜索 指向成员变量的指针 的相关内容)。
由于当初实现时没有相关经验,甚至其中的offsetof宏也是我自己杜撰的;后来与c++代码混编时被编译器提示用成员变量指针代替offsetof宏,才知道自己又重新发明了轮子。

不过,用c++实现的话,最好的办法还是采用“序列化”模式(参考c++流设计思路;不过它是“流”向普通文件,我是“流”向xml格式缓冲区而已);所以也懒得重构这个东东了,干脆用类似机制重新写了个通用的“可序列化到xml”基类。

另外,微软新近推出的WPF,从它的核心技术之一“依赖属性(DependencyProperty)”的声明、使用方式看,其内部实现显然也采用了类似的思路。


PS:
指向成员变量的指针语法如下:int aa::*ptr = &aa::I1
以后,若有aa x1;则 *(x1.ptr)就相当于x1.I1
这个办法可以避免传入的结构体类型不匹配导致程序崩溃(俺当初是干脆引入模板参数推导机制,搞了个c+泛型的BT东东-_-|||;这个丑陋实现也是后来重写时改用 可序列化到xml 类机制的原因之一)。

这是offsetof宏的定义:
#define offsetof(structName,item) (size_t)&(((structName *)0)->item)

原理: 强制转换0为structName *;则 &(((structName *)0)->item)就是item相对于结构体首字节的偏移量;为避免指针相加警告,因而又将其强制转换为size_t。
作者: chbc88    时间: 2008-07-08 14:02
楼上一写就一大片呀
作者: bosi_cat    时间: 2008-07-09 23:38
谢谢大家,好像有点眉目了,我再琢磨琢磨
作者: blackuhlan    时间: 2008-07-10 07:36
我写过一个代码,根据变量类型和内存对齐原则,可以顺序访问结构体内变量的指针,不知道楼主需要这个不如果需要,我可以告诉你怎么做。限制是:必须顺序访问,必须知道结构体变量类型,或者其长度
作者: blizzard213    时间: 2008-07-10 19:37
原帖由 bosi_cat 于 2008-7-8 12:32 发表
有没有人玩过这样的问题:有一个结构体,动态的取一个成员变量的值,怎么实现?
比如:
struct aaa { int a ; int b } bbb;

char name[4];
strcpy( name, "b" );

怎么获取到name这个变量指定的成员的值?



看不懂
bbb从头到尾就出现了一次
作者: nicolas.shen    时间: 2008-07-10 20:17
就是对象序列化。
作者: piscesm    时间: 2008-07-10 20:26
学习
作者: bosi_cat    时间: 2008-07-22 22:09
知道类型或者是长度,外加offsetof应该可以弄出来,算了,我使用别的办法搞了,代码这个东西,其实只要实现功能就可以了
作者: nuying117    时间: 2008-07-22 23:33
发错了,不知道怎末删除




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2