[英]What are the differences between these two typedef styles in C?
我很好奇當typedefing一個枚舉或結構時,這里的區別是什么。 這兩個塊之間在語義上有什么區別嗎?
這個:
typedef enum { first, second, third } SomeEnum;
還有這個:
enum SomeEnum { first, second, third };
typedef enum SomeEnum SomeEnum;
結構相同的交易。 我已經看到兩者都在使用,他們似乎都在C或Objective-C中做同樣的事情。 是否存在真正的差異,或者只是偏好您可以使用哪種風格?
不同之處在於第二種方法聲明了一個名為enum SomeEnum
的類型,並且還聲明了一個typedef-name SomeEnum
- 該類型的別名。 它實際上可以組合成等效的單行程
typedef enum SomeEnum { first, second, third } SomeEnum;
這很明顯,兩種方法之間的唯一區別是enum
關鍵字后面是否有名稱。 使用第二種方法,您可以使用SomeEnum e
或enum SomeEnum e
(無論您喜歡哪種方式)聲明該枚舉類型的對象。
第一種方法僅為最初的匿名枚舉類型聲明typedef-name SomeEnum
,這意味着您僅限於SomeEnum e
聲明。
因此,只要您在聲明中僅使用typedef-name SomeEnum
,兩者之間就沒有區別。 但是,在某些情況下,您可能必須使用類型enum SomeEnum
的完整原始名稱。 在第一種方法中,該名稱不可用,因此您將失去運氣。
例如,如果在上述聲明之后,您還在某個嵌套范圍中聲明了名為SomeEnum
的變量
int SomeEnum;
變量的名稱將隱藏枚舉的typedef-name,從而使此聲明非法
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
。
是的,存在語義差異。 第二個片段聲明了標記標識符,但第一個標識符沒有。 兩者都聲明一個普通的標識符。
這意味着,對於第一個,此代碼無效,但對於第二個,它是:
enum SomeEnum foo;
據我所知,代碼中它們之間沒有其他語義差異。 對於結構和聯合,遞歸類型需要第二種形式,可能與一個聲明中的typedef結合使用
typedef struct node {
struct node *parent; // refer to the tag identifier
} node;
普通標識符在struct的說明符中尚不可見,因此您需要通過已聲明的標記標識符來引用該結構。 標簽標識符通過在“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 ++相反),並且它們需要引用現有類型,因此它們不能用於創建前向聲明。
唯一真正的區別是,在第二種情況下,您可以使用以下內容:
enum SomeEnum x;
而第一個只支持:
SomeEnum x;
人誰已經用C寫很長的時間,定義一個struct
沒有struct
往往關鍵詞“感覺”奇怪...
第一個表單創建一個匿名enum
類型並SomeEnum
創建一個SomeEnum
別名。
第二種形式創建enum SomeEnum
類型和SomeEnum
別名。
(在C中,類型有單獨的命名空間。也就是說, struct Foo
與enum Foo
不同,它與Foo
不同。)
對於struct
這比enum
更重要,因為如果你的struct
是自引用的,你需要使用第二種形式。 例如:
struct LinkedListNode
{
void* item;
struct LinkedListNode* next;
};
typedef struct LinkedListNode LinkedListNode;
第一種形式無法實現上述目標。
對於struct
真正的區別不僅僅在於命名。
這是有效的C:
struct SomeEnum { struct SomeEnum *first; };
這不是:
typedef struct { SomeEnum *first; } SomeEnum;
having a definition for the struct. 添加到user207442的評論,有可能為源代碼模塊,而為結構的定義聲明式“結構FOO *”的變量。 這樣的模塊將無法取消引用這樣的指針,但可以將它們傳遞給其他模塊或從其他模塊傳遞。
例如,可以使用“typedef struct _USERCONSOLE * USERCONSOLE;”來為頭文件定義類型“USERCONSOLE”。 代碼表示#include的頭文件可以包含USERCONSOLE類型的變量,並將這些變量傳遞給/來自知道_USERCONSOLE實際是什么的模塊,而頭文件不必暴露結構的實際定義。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.