【问题标题】:How to dynamically create and read structs in C?如何在 C 中动态创建和读取结构?
【发布时间】:2009-04-22 15:05:24
【问题描述】:

我怎样才能做这样的事情(只是一个例子):

any_struct *my_struct = create_struct();
add_struct_member(my_struct, "a", int_member);
add_struct_member(my_struct, "b", float_member);

这样我就可以“从外部”(地址addressOfMyStruct)加载和使用具有此处给定结构的结构实例?

any_struct_instance *instance = instance(my_struct, addressOfMyStruct);
int a = instance_get_member(instance, "a");
float b = instance_get_member(instance, "b");

我也希望能够以这种方式动态创建结构实例。

我希望很清楚我想要做什么。我知道C/Invoke 可以做到这一点,但是有没有单独的库可以做到这一点?

【问题讨论】:

  • 顺便说一下,API 只是一个例子。它不需要是完全相同的 API。

标签: c struct


【解决方案1】:

实际上,在 C 中演示使这项工作的代码对于 SO 帖子来说有点过于复杂。但解释基本概念是可行的。

您在这里真正创建的是一个模板化的属性包系统。要保持这种状态,您需要做的一件事是一些关联结构,例如哈希表。我会说使用 std::map 但你提到这是一个仅限 C 的解决方案。为了讨论起见,我只是假设您有某种可用的哈希表。

“create_struct”调用需要返回一个结构,该结构包含一个指向哈希表的指针,这使得const char* 本质上是一个size_t。此映射定义了创建结构的新实例所需的内容。

“insance”方法本质上将创建一个新的哈希表,其成员数量与模板哈希表相同。让我们暂时抛开懒惰的评估,并假设您预先创建了所有成员。该方法将需要遍历模板哈希表,为每个条目添加一个成员并分配指定大小的内存块。

instance_get_member 的实现将简单地按名称在地图中进行查找。不过,签名和使用模式将需要更改。 C 不支持模板,必须选择可以表示所有数据的通用返回类型。在这种情况下,您需要选择void*,因为这就是需要存储内存的方式。

void* instance_get_member(any_struct_instance* inst, const char* name);

您可以通过添加 envil 宏来模拟模板来改善这一点

#define instance_get_member2(inst, name, type) \
  *((type*)instance_get_member((inst),(name)))
...
int i = instance_get_member2(pInst,"a", int);

【讨论】:

  • 谢谢,这听起来并不难。但是,我是否有可能偶然发现填充问题或类似问题?
  • @frw,你不应该因为你使用 malloc 为结构数据分配空间。由于它存储在字典中,因此每个成员应该有一个 alloc。只有在连续的内存块中填充它们时才会真正出现填充问题。你可以采用这种方法,尽管我会避免它,特别是因为包装原因;)
  • 好吧,我会读一些关于包装的书,看看我要做什么。但是,使用 C/Invoke 将是最简单的解决方案。现在谢谢!
【解决方案2】:

到目前为止,您已经定义了一个问题,剩下的就是一些(在某些部分有点棘手)实现。您只需要跟踪信息:

typedef struct {
    fieldType type;
    char      name[NAMEMAX];
    /* anything else */
} meta_struct_field;
typedef struct {
    unsigned          num_fields;
    meta_struct_field *fields;
    /* anything else */
} meta_struct;

然后create_struct()meta_struct 分配内存并将其初始化为0,add_struct_member()my_struct.fields 上执行alloc()/realloc() 并递增my_struct.num_fields。其余部分以同样的方式进行。

您还需要union 中的meta_struct_field 来保存实例中的实际值。

【讨论】:

    【解决方案3】:

    我很久以前做过一些。

    我这样做的方法是生成包含结构定义的代码,以及用于访问它的所有例程,然后“动态”编译并链接到 DLL,然后动态加载该 DLL。

    【讨论】:

    • 不幸的是,这对我来说是没有选择的。无论如何谢谢:)
    猜你喜欢
    • 1970-01-01
    • 2020-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-06-19
    • 2012-07-28
    • 2019-05-19
    • 1970-01-01
    相关资源
    最近更新 更多