多態結構在C中很常見,但通常涉及顯式的強制轉換,它允許意外拋出不兼容的結構。編譯時檢查C中的多態類型?
struct ID {
char name[32];
};
struct IntID {
struct ID id_base;
int value;
}
struct FloatID {
struct ID id_base;
float value;
}
void id_name_set(ID *id, const char *name)
{
strlcpy(id->name, name, sizeof(id->name));
}
/* macro that happens to use 'id_name_set', this is a bit contrived */
#define ID_NAME_SET_AND_VALUE(id, name, val) \
do { \
id_name_set((ID *)id, name); \
id->value = val; \
} while(0)
void func(void)
{
struct { int value; } not_an_id;
/* this can crash because NotID doesn't have an ID as its first member */
ID_NAME_SET_AND_VALUE(not_an_id, "name", 10);
}
這裏的問題是,我們不能鍵入檢查在宏id
參數針對單一類型的,因爲它可能是一個ID
或與ID
作爲其第一個成員的任何結構。
我見過的很多代碼只是簡單地將結果轉換到整個地方的結構,但似乎有可能有一個更可靠的方法。
有沒有辦法在編譯時檢查?
注意,對於這個問題的目的,我們可以假設所有的結構,因爲他們繼承的結構使用相同的成員名稱。
注意,我希望能夠使用這樣的事情...
# define CHECK_TYPE_POLYMORPHIC(val, member, struct_name) \
(void)(_Generic((*(val)), \
/* base-struct */ struct_name: 0, \
/* sub-struct */ default: (_Generic(((val)->member), struct_name: 0))))
/* --- snip --- */
/* check that `var` is an `ID`, or `var->id_base` is */
CHECK_TYPE_POLYMORPHIC(var, id_base, ID);
...但失敗了ID
類型的default
情況 - 因爲他們沒有id
會員。
到目前爲止,我發現要做到這一點的唯一方法是對所有結構體的完整列表進行類型檢查,這在某些情況下不是理想的(可能很多 - 或者是本地定義的,因此宏不知道,參見:Compile time check against multiple types in C?)。
我不禁覺得這是領導下的歧途。如果你想要C++,可以使用C++。 – 2014-09-24 05:26:33
@Jonathan Leffler。我知道,也許我試圖做的事情不是真的被C支持,但我並不真的有興趣轉向另一種語言,如果不可能對類型檢查進行類型檢查,我可以通過檢查struct的列表已經有了,但是如果有可能爲現有的C代碼庫添加一些額外的類型檢查,那麼爲什麼不呢? – ideasman42 2014-09-24 06:30:01
您是否閱讀過GObject或gtk + 2.0/gtk + 3.0的任何文檔。他們做到這一點,不要重新發明車輪。只是他們的代碼它的版權是gnu小gpl。 – rhubarbdog 2014-09-26 04:14:13