2010-07-06 74 views
13

我很好奇這裏的區別是什麼時,typedefing枚舉或結構。這兩個塊之間在語義上是否有區別?C中這兩個typedef樣式有什麼區別?

此:

typedef enum { first, second, third } SomeEnum; 

這:

enum SomeEnum { first, second, third }; 
typedef enum SomeEnum SomeEnum; 

同樣的協議的結構。我已經看到兩個都在使用,他們似乎在C或Objective-C中做了同樣的事情。有沒有真正的差異,或者它只是您可以使用哪種風格的首選?

回答

15

區別在於第二種方法聲明瞭名爲enum SomeEnum的類型,並且還聲明瞭typedef名稱SomeEnum - 該類型的別名。它實際上可以組合成一個相當於班輪

typedef enum SomeEnum { first, second, third } SomeEnum; 

這使得它相當明顯的是,這兩種方法之間的唯一區別是是否有在enum關鍵字後面的名稱。使用第二種方法,您可以使用SomeEnum eenum SomeEnum e(無論您喜歡哪個)聲明該枚舉類型的對象。

第一種方法僅聲明typedef-name SomeEnum爲最初的匿名枚舉類型,這意味着您僅限於SomeEnum e聲明。

因此,只要您在聲明中只使用typedef-name SomeEnum,兩者之間就沒有區別。但是,在某些情況下,您可能需要使用類型enum SomeEnum的完整原始名稱。在名字不可用的第一種方法中,所以你會走運。

例如,如果上述聲明之後,你還聲明在一些嵌套的範圍

int SomeEnum; 

變量的名稱將隱藏枚舉的typedef的名稱命名SomeEnum變量,從而使這一聲明非法

SomeEnum e; /* ERROR: `SomeEnum` is not a type */ 

但是,如果你聲明枚舉時使用的第二種方法,您可以使用完整的類型名稱

解決此問題
enum SomeEnum e; /* OK */ 

如果您在聲明枚舉類型時使用第一種方法,則這是不可能的。

當結構使用時,struct後的名稱是必須的,當你需要一個自引用類型(即包含一個指向同一類型的類型),像

typedef struct SomeStruct { 
    struct SomeStruct *next; 
} SomeStruct; 

最後,在第二種方法typedef名稱是完全可選的。您可以簡單地聲明

enum SomeEnum { first, second, third }; 

並且只是在每次需要引用此類型時都使用enum SomeEnum

7

是的,存在語義差異。第二個片段聲明瞭一個標籤標識符,但第一個沒有。兩者都聲明一個普通的標識符。

這意味着,第一個,這個代碼是無效的,但第二,它是:

enum SomeEnum foo; 

據我所知,沒有在你的代碼它們之間沒有其他的語義差別。對於結構和聯合,第二種形式,也許在一個聲明中的typedef相結合,需要對遞歸類型

typedef struct node { 
    struct node *parent; // refer to the tag identifier 
} node; 

普通標識符沒有在結構中的符可見,這樣的話你需要參考由已經聲明的標籤標識符構造。標籤標識符是通過在「struct」,「union」或「enum」之前加引號來引用的,而普通標識符是不帶前綴的(因此名稱爲「普通」)。

除了分離引用的那些參考值結構,聯合和枚舉的標識,標籤標識也可用於創建前向聲明:

/* forward declaration */ 
struct foo; 

/* for pointers, forward declarations are entirely sufficient */ 
struct foo *pfoo = ...; 

/* ... and then later define its contents */ 
struct foo { 
    /* ... */ 
}; 

typedef名稱不能在多次宣佈相同的範圍(與C++相反,它們可以),並且它們需要引用現有類型,以便它們不能用於創建前向聲明。

4

唯一真正的區別是,在第二種情況下,你可以使用類似:而第一隻支持

enum SomeEnum x; 

SomeEnum x; 

的人誰一直在寫很長一段時間,定義一個struct而沒有struct關鍵字往往「感覺」奇怪......

2

第一種形式創建一個匿名enum類型併爲其創建一個SomeEnum別名。

第二種形式爲其創建enum SomeEnum類型和SomeEnum別名。

(在C中,類型有單獨的命名空間,即struct Foo不同於enum Foo,與Foo不同。)

這對於struct s比enum更重要,因爲如果您的struct是自引用的,則需要使用第二個表單。例如:

struct LinkedListNode 
{ 
    void* item; 
    struct LinkedListNode* next; 
}; 

typedef struct LinkedListNode LinkedListNode; 

以上將不可能與第一種形式。

0

對於struct s有一個真正的區別,不僅僅是命名。

這是合法的C:

struct SomeEnum { struct SomeEnum *first; }; 

這不是:

typedef struct { SomeEnum *first; } SomeEnum; 
0

添加到user207442的評論,有可能爲源代碼模塊聲明類型的變量「結構FOO *」無有結構的定義。這樣的模塊將無法取消引用這些指針,但可能會將它們傳遞給其他模塊。

例如,可以使用「typedef struct _USERCONSOLE * USERCONSOLE;」來定義類型爲「USERCONSOLE」的頭文件。包含該頭文件的代碼可以包含USERCONSOLE類型的變量,並將這些變量傳遞給/知道_USERCONSOLE實際是什麼的模塊,而無需頭文件公開實際的結構定義。