在运行时访问任何结构成员

时间:2010-04-08 00:08:48

标签: c++ c data-structures pointers struct

是否可以在不知道其成员变量名称的情况下访问结构或类的单个成员? 我想做一个“offsetof(struct,tyname)”而没有结构名称或成员变量名称硬编码其他东西。 感谢。

6 个答案:

答案 0 :(得分:4)

不确定。如果你有一个结构,并且你知道偏移量和成员变量的类型,你可以使用指针访问它。

struct my_struct {
    int member1;
    char member2;
    short member3;
    char member4;
}

...

struct my_struct obj;
short member3 = *((short*)((char*)&obj + 5));

这将获得member3的值,这是x86计算机上obj开头的5个字节。但是,你要小心。首先,如果结构发生变化,那么您的数据将是垃圾。我们在各地都在施展,所以你没有任何类型安全,如果出现问题,编译器就不会警告你。您还需要确保编译器不打包结构以将变量与字边界对齐,否则偏移将发生变化。

这不是一件令人愉快的事情,如果我是你,我会避免这样做,但是,可以这样做。

答案 1 :(得分:1)

C和C ++是编译语言,没有内置的“反射”功能。这意味着无论您做什么以及如何操作,路径总是从显式硬编码值开始,即成员名称或编译时偏移值。这意味着如果你想根据某个运行时键选择一个struct成员,你别无选择,只能手动创建某种类型的映射,将映射键值映射到标识具体struct成员的东西。

在C ++中,为了在运行时识别结构成员,您可以使用此类功能作为指向成员的指针。在C中,您唯一的选择是使用偏移值。

另一个问题当然是指定成员的类型,如果您的成员可以有不同的类型。但是你没有提供任何细节,所以我不能说你是否需要处理它。

答案 2 :(得分:1)

几年前我们遇到了类似的问题:我们想要反思的庞大的配置信息结构。所以我们编写了一个Perl脚本来查找结构,解析其成员,并输出一个看起来像这样的C ++文件:

struct ConfField
{    const char* name;
     int type;
     size_t offset;
};

ConfField confFields[] = {
    { "version", eUInt32, 0 },
    { "seqID", eUInt32, 4 },
    { "timestamp", eUInt64, 8 },
    // ... lots more ...
    { 0, 0, 0 }
};

我们会使用gcc -E的输出提供脚本。

现在,我知道gccxml可以输出一个XML文件,代表gcc可以编译的任何C ++源代码,因为它实际上使用g ++前端来进行解析。因此,我建议将其与XML解析脚本配对(我将Python与lxml库一起使用),以找出您想知道的有关C ++源代码的所有内容。

答案 3 :(得分:0)

在代码中的某处,您需要引用结构中的数据成员。但是,您可以创建一个变量,该变量是指向结构数据成员的指针,从那时起,您不再需要按名称引用它。

struct foo
{
    int member1;
    int member2;
};

typedef int (foo::*intMemberOfFoo);

intMemberOfFoo getMember()
{
    if (rand() > RAND_MAX / 2) return &foo::member1;
    else return &foo::member2;
}

foo f;
void do_somthing()
{
    intMemberOfFoo m = getMember();
    f.*m = 0;
}

答案 4 :(得分:0)

技术答案是肯定的,因为C ++是Turing-complete,如果你足够努力,你几乎可以做任何事情。更实际的答案可能是“不”,因为没有安全简便的方法可以完全按照自己的意愿行事。

我同意GMan。你究竟想做什么让你认为你需要这种技术?

答案 5 :(得分:0)

嗯,你必须首先设置一些东西,但它可以完成。扩展萨米尔的回应

struct my_struct {
    int member1;
    char member2;
    short member3;
    char member4;
}

你可以创建一个偏移表:

my_struct tmp;
int my_struct_offsets[4]={
  0,
  (char*)&(tmp.member2)-(char*)&(tmp.member1),
  (char*)&(tmp.member3)-(char*)&(tmp.member1),
  (char*)&(tmp.member4)-(char*)&(tmp.member1)
}

这将考虑不同系统上的不同路线