2009-04-22 90 views
6

我怎樣才能做這樣的事情(只是一個例子):如何在C中動態創建和讀取結構?

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能夠做到這一點,但有沒有一個單獨的庫來做到這一點?

+0

順便說一句,API只是一個例子。它不需要完全相同的API。 – user94405 2009-04-22 15:37:31

回答

6

實際上,演示代碼以使其在C語言中工作對於SO帖子來說有點過於牽扯。但是解釋基本概念是可行的。

你真正在這裏創建的是一個模板化的財產袋系統。爲了保持這一點,你需要做的很多事情就是像散列表這樣的輔助結構。我會說std :: map去,但你提到這是一個C唯一的解決方案。爲了討論的緣故,我只是假設你有一些可用的散列表。

「create_struct」調用將需要返回一個結構,該結構包含一個指向散列表的指針,該散列表使const char*基本上成爲size_t。這張圖定義了你爲了創建結構的新實例而需要的東西。

「insance」方法本質上會創建一個新的哈希表,它具有與模板哈希表相同數量的成員。讓我們暫時把懶惰的笑話放在窗口外面,並假設你預先創建了所有成員。該方法需要遍歷模板散列表,爲每個條目添加一個成員,並且malloc指定一個大小的內存塊。

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); 
+0

謝謝,這聽起來並不難。但是,我有可能偶然發現填充或類似的問題嗎? – user94405 2009-04-22 15:32:55

+0

@frw,你不應該因爲你使用malloc來爲struct數據分配空間。由於它存儲在字典中,因此每個成員應該有一個alloc。填充問題只有在你將它們填充到連續的內存塊中時纔會出現。你可以採取這種方法,雖然我會避免它,特別是因爲包裝的原因;) – JaredPar 2009-04-22 16:56:58

1

你已經走了這麼遠定義,所有剩下的問題是有點(以有點難一些部分)的實施。你只需要保持信息跟蹤:

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和增量my_struct.num_fieldsalloc()/realloc()。其餘的部分如下。

您還需要meta_struct_field中的union在實例中保存實際值。

0

很久以前,我做了一些。

我這樣做的方式是生成包含結構定義的代碼,以及所有用於訪問它的例程,然後將其編譯並鏈接到「動態」DLL中,然後動態加載該DLL。