2016-12-05 53 views
0

我有兩個定義的結構,它們都有一個共同的字段。 typedef struct entry entry;共享相同變量的結構的函數指針

typedef struct example { 
    entry* list_e; 
    int nb_elements; 
    int nb_mllc; 
} example; 

typedef struct mystruct { 

    entry* list_e; 
    int nb_elements; 
    int nb_mllc; 
} mystruct; 

是可能的是,我寫一個函數使得或者MYSTRUCT或例如可以是一個變量的類型?在該功能我正在填充列表「項」,所以我知道我可以通過編寫方法

void add_entry(entry** list_e, int* nb, int* nb_mllc){ 

     //fill the entries 
     if (*nb == *nb_mllc) { 
      //realloc list_e 
     } 
} 

做,但然而,這看起來像一個骯髒的解決方案給我的話,我將不得不調用函數像

 example* example; //malloc and null pointer checking left out 

    add_entry(&example->list_e, &example->nb_elements, &example->nb_mllc); 

然後也mystruct,但我寧願沒有拆分結構的變量作爲函數參數。是否有可能使以某種方式例如和MYSTRUCT相同類型的,所以我可以然後使整個結構作爲參數

+0

您的類型「示例」和「mystruct」似乎除了它們的標記以外都是相同的。爲什麼不選擇一個並在任何地方使用? –

+0

你說結構只共享一個字段,但它們似乎具有相同的確切結構。這是一個錯字或什麼? – yLaguardia

+0

你有一個異構的鏈表,這是真的嗎?您希望如何恢復鏈接的數據而不失去其類型?你將需要實現某種類型的自省,對吧? –

回答

1

是可能的是,我寫一個函數使得或者MYSTRUCT或例如可以是一個變量的類型?

編號每個函數參數都只有一種類型。即使您的兩個結構具有相同類型的成員(按相同順序,具有相同名稱),但由於具有不同的struct標籤,因此它們是不同的,不兼容的類型。 (另一方面,typedefed名稱中的差別與此無關。)接受這些類型之一的參數或指向該類型的指針的函數不能將另一個類型的參數接受爲相同的參數。

有人可能會建議將指向其中一種類型的指針指向其他類型的指針,以便能夠將它傳遞給您的假設函數。儘管在實踐中可能會產生所需的結果,但它違反了C嚴格的別名規則,因此會產生未定義的行爲。這種行爲可能會讓你陷入一個積極優化的編譯器。

你至少有三種選擇:

使用相同的結構

沒有理由從你的問題,爲什麼你需要不同的類型,因爲這兩種類型的問題,只有在不同的明顯他們的結構標籤。如果你只是選擇一個並在任何地方使用它,那麼問題就會消失。如果您願意,您可以使用typedef多種別名;它不會影響你在任何特定地方使用那些代碼的有效性。

嵌入相同的結構

這可能是因爲你已經通過去除實際上不同的兩種類型的元素過於簡單化你的代碼。在這種情況下,可以嵌入包含這些值的共同結構到更大的結構,如下所示:

struct list_data { 
    entry* list_e; 
    int nb_elements; 
    int nb_mllc; 
}; 

typedef struct example { 
    struct list_data list_data; // must be first 
    char *characters; 
} example; 

typedef struct mystruct { 
    struct list_data list_data; // must be first 
    int x, y, z; 
} mystruct; 

Ç保證的結構的第一個成員的表示將在整體結構的的第一個字節開始表示。因此,只要在後一種情況下仔細轉換爲正確的類型,您可以(原則上)安全地在指向第一個成員的指針和指向整體結構的指針之間來回轉換。

使用節點類型與鑑別和工會

鑄造一般是設計不良的標誌。如果你不能在任何地方使用相同的類型,那麼它可能是一個更好的計劃轉內而外的嵌入想法:

typedef struct example { 
    char *characters; 
} example; 

typedef struct mystruct { 
    int x, y, z; 
} mystruct; 

struct list_data { 
    entry* list_e; 
    int nb_elements; 
    int nb_mllc; 
    _Bool is_mystruct; 
    union { 
     example *example; 
     mystruct *mystruct; 
    }; 
}; 

現在你有一個單一的類型,struct list_data,你可以通過一個單一的連接成列表功能集。該類型可以參考(或嵌入,如果您願意的話)examplemystruct,其中成員is_mystruct可以消除實際存儲的內容。或者,如果從上下文中可以看出哪種類型存儲,則可以刪除is_mystruct

+0

真的非常感謝你在這裏的詳細描述和解釋。 但是我想我可能並不真正瞭解第二個例子應該如何工作。所以我有兩個結構,第一個元素是'list_data'。所以你試着說,如果我有一個 'mystruct * struct;',我可以將它轉換爲'(list_data)struct' – malajedala

+0

我以前從未使用過聯盟,但我知道它們被定義爲它們可以是給定的變量。但是,我不應該爲工會分配一個標籤,以便通過我的結構訪問它?你錯過了將list_data添加爲結構變量,還是在這種情況下想要這麼做? – malajedala

+0

@malajedala,工會和結構遵循關於標籤的相同規則:它們可以被標記,但它們不需要被標記。此外,在C2011中,那些在其他結構或聯合中出現未標記的內容也可以是* anonymous *,就像我的示例代碼中的情況一樣。然後訪問聯合成員,就好像它們是外部結構的直接成員一樣。這主要是一個便利功能,如果你願意,你可以給工會一個名字並通過它訪問成員。另一方面,給它一個標籤對你沒有任何幫助。 –