我是C編程的初學者,但我想知道在定義結構時使用typedef與不使用typedef有何區別。在我看來,實際上沒有什麼區別,他們完成了同樣的任務。typedef結構與結構定義
struct myStruct{
int one;
int two;
};
與
typedef struct{
int one;
int two;
}myStruct;
我是C編程的初學者,但我想知道在定義結構時使用typedef與不使用typedef有何區別。在我看來,實際上沒有什麼區別,他們完成了同樣的任務。typedef結構與結構定義
struct myStruct{
int one;
int two;
};
與
typedef struct{
int one;
int two;
}myStruct;
常見成語是同時使用:
typedef struct X {
int x;
} X;
它們是不同的定義。爲了使討論更加清楚我會分裂了一句:
struct S {
int x;
};
typedef struct S S;
在第一行要定義的結構命名空間中的標識符S
(而不是在C++意義上的)。您可以使用它,並通過定義爲struct S
參數的類型來定義新定義類型的變量或函數參數:
void f(struct S argument); // struct is required here
第二行增加了一個類型別名S
在全局命名空間,從而允許您只寫:
void f(S argument); // struct keyword no longer needed
注意,因爲這兩個標識符名稱空間是不同的,定義S
無論是在結構和全球空間是不是一個錯誤,因爲它不是重新定義相同的標識符,而是創造了一個不同的標識符一個不同的地方。
賺取差價更清晰:
typedef struct S {
int x;
} T;
void S() { } // correct
//void T() {} // error: symbol T already defined as an alias to 'struct S'
您可以定義與結構的名稱相同的功能的標識都保存在不同的空間,但你不能用相同的名稱定義一個函數當這些標識符發生碰撞時。
在C++中,它稍有不同,因爲定位符號的規則已經微妙地改變了。 C++仍保持着兩個不同的標識符空間,但與C,當你只定義在類標識符空間內的符號,你是不是需要提供結構/ class關鍵字:
// C++
struct S {
int x;
}; // S defined as a class
void f(S a); // correct: struct is optional
是什麼改變搜索規則,而不是定義標識符的位置。編譯器將搜索全局標識符表,並且在S
尚未找到之後,它將在類標識符內搜索S
。
以同樣的方式的行爲之前給出的代碼:
typedef struct S {
int x;
} T;
void S() {} // correct [*]
//void T() {} // error: symbol T already defined as an alias to 'struct S'
在第二行中的S
函數的定義之後,結構s不能是由編譯器自動解決,並創建一個對象或定義類型的參數必須退回到包括struct
關鍵字:
// previous code here...
int main() {
S();
struct S s;
}
偉大的答案顯示我也爲什麼我想要typedef,所以它不能被覆蓋作爲一個函數,謝謝:)) – 2013-07-20 12:41:42
@AlexanderVarwijk:你想'typedef',以避免需要結構'或'enum' 。如果您使用的命名約定允許使用相同名稱的函數和類型,那麼您可以做的最好的事情就是檢查如何命名程序的元素。 – 2013-07-20 18:45:14
我的命名約定應該確保不會發生,比對不起更安全:) – 2013-07-21 12:56:43
的typedef
,因爲它與其它構建體中,用來給一個數據類型的新名稱。在這種情況下,它是爲了使代碼更清潔主要完成:
struct myStruct blah;
與
myStruct blah;
在C(不是C++),你必須聲明結構變量,例如:
struct myStruct myVariable;
爲了能夠使用myStruct myVariable;
相反,你可以typedef
的結構:
typedef struct myStruct someStruct;
someStruct myVariable;
您可以結合struct
定義和typedef
的IT在其中宣佈匿名struct
和typedef
的IT一條語句。
typedef struct { ... } myStruct;
最後一塊代碼不等同於前面的代碼。在最後一行中,您將一個類型別名'myStruct'定義到一個未命名的結構中。兩個版本之間存在(非常)細微的差別。 – 2009-11-04 17:52:40
dribeas:我在句子「......一個聲明**匿名結構**和......」的單句中說明了這個微妙的區別 – 2009-11-04 18:10:33
真的,我似乎跳過了那部分:) – 2009-11-05 07:27:36
當您使用struct
時區別進來。
你必須做的第一種方式:
struct myStruct aName;
第二種方法允許你刪除關鍵字struct
。
myStruct aName;
如果使用struct
無typedef
,你總能寫
struct mystruct myvar;
這是非法的,如果您使用typedef
你不需要寫
mystruct myvar;
struct
前綴了。
給點答案。 – 2017-06-03 14:41:51
對於後面的示例,在使用結構時省略了struct關鍵字。因此,在你的代碼隨處可見,你可以這樣寫:
myStruct a;
,而不是
struct myStruct a;
這節省一些打字,而可能是更具可讀性,但是這是一個品味問題
在C的結構,聯合類型說明符關鍵字和所列舉的都是強制性的,即你總是有前綴的TY pe的名稱(其標籤)與struct
,union
或enum
在引用類型時。
您可以通過使用typedef
來擺脫關鍵字,這是一種信息隱藏形式,因爲在聲明對象時實際類型將不再可見。
因此建議(見例如Linux kernel coding style guide,第5章)只有當 你真正想要向隱藏這個信息,不只是爲了節省幾個按鍵做到這一點。
的時候應該使用一個typedef
將其永遠只與相應的存取器函數/宏使用不透明類型的一個例子。
Linux內核編碼風格指南供參考:http://www.kernel.org/doc/Documentation/CodingStyle – 2010-07-21 20:45:37
Linux內核編碼風格文檔已被移至https://www.kernel.org/doc/Documentation/process /coding-style.rst – 2017-05-11 10:48:56
另一個不同之處不指出的是,給結構的名稱(即結構MYSTRUCT),您還可以提供前進的結構的聲明。因此,在其他文件中,您可以編寫:
struct myStruct;
void doit(struct myStruct *ptr);
而不必訪問定義。我的建議是你把你的兩個例子:
typedef struct myStruct{
int one;
int two;
} myStruct;
這給你一個更簡潔的類型名字的便利,但仍允許您如果需要使用完整的結構名稱。
有一些方法可以用typedef做前向聲明:'typedef struct myStruct myStruct;';然後(稍後):'struct myStruct {...};'。你可以在'typedef'之後使用它* * struct myStruct' *或者* myStruct'(但是類型是不完整的,直到定義)。 – 2015-02-10 14:20:28
值得一提的是,儘管(概念上)自動輸入了定義標籤並在單個「符號空間」中放置了「SomeThing」和「Something」,但C++確實爲手動typedef SomeThing重新定義了明確的限制到'struct SomeThing' ... ...否則你可能會認爲這會產生一個關於碰撞名稱的錯誤。資料來源:http://stackoverflow.com/a/22386307/2757035我想這是完成的(稍微徒勞!)向後兼容的原因。 – 2016-04-09 16:52:02
@underscore_d:當時,人們認識到代碼的價值可以與C和C++一樣好,並且希望避免在兼容性方面造成不必要的障礙。可悲的是,這種想法已不再流行。 – supercat 2017-04-15 20:53:15
下面的代碼與別名myStruct
創建一個匿名結構:
typedef struct{
int one;
int two;
} myStruct;
您不能引用它,而不別名,因爲你不指定結構的標識符。
不能使用向前聲明與typedef struct
。
的struct
本身就是一個匿名類型,所以你不要有一個實際的名稱轉發申報。
typedef struct{
int one;
int two;
} myStruct;
像這樣的向前聲明將無法工作:
struct myStruct; //forward declaration fails
void blah(myStruct* pStruct);
//error C2371: 'myStruct' : redefinition; different basic types
struct
和typedef
是兩個完全不同的事情。
的struct
關鍵字用來定義,或指代,結構類型。例如:
struct foo {
int n;
};
創建一個名爲struct foo
的新類型。名稱foo
是標籤;這是有意義的,只是當它立即被struct
關鍵字之前,因爲標籤和其他標識是在不同的的名稱空間。 (這與namespace
的C++概念相似但限制更多)。
儘管名稱存在,但它並沒有定義新的類型;它僅爲現有類型創建一個新名稱。例如,給定:
typedef int my_int;
my_int
是int
一個新的名字; my_int
和int
都是正好是是同一類型。同樣,鑑於上述struct
定義,你可以寫:
typedef struct foo foo;
類型已經有一個名字,struct foo
。 typedef
聲明給出了相同類型的新名稱foo
。
的語法允許一個struct
和typedef
合併成一個單一聲明:
typedef struct bar {
int n;
} bar;
這是一個常見的成語。現在你可以參考這個結構類型struct bar
或只是bar
。
請注意,typedef名稱在聲明結束前不可見。如果結構包含一個指向自身,則必須使用struct
版本來參考一下吧:
typedef struct node {
int data;
struct node *next; /* can't use just "node *next" here */
} node;
一些程序員會使用不同的標識符的結構標記和typedef名。在我看來,這沒有什麼好的理由。使用相同的名稱是完全合法的,並且使得它們更清楚,它們是相同的類型。如果必須使用不同的標識符,至少使用一個一致的約定:
typedef struct node_s {
/* ... */
} node;
(就個人而言,我更喜歡省略typedef
並參考類型struct bar
的typedef
節省一點打字,但它隱藏了一個事實如果你希望類型是不透明的,這可能是一件好事,如果客戶端代碼是通過名字引用成員n
,那麼它不是不透明的;它顯然是一個結構,在我的意見認爲它是一種結構,但很多聰明的程序員在這一點上不同意我的觀點,請準備閱讀並理解以任何一種方式編寫的代碼。)
(C++有不同的規則。給定struct blah
的聲明,即使沒有typedef,也可以將其類型稱爲blah
。使用typedef可能會讓你的C代碼更像C++ - 如果你認爲這是一件好事。)
這個答案幫助我更好地理解了爲什麼C89庫和Linux內核更可能使用'struct mystruct_t {}'而不是'typedef struct {} mystruct_t'。 – 2016-07-25 13:05:51
我看到一些澄清是爲了這個。 C和C++不會以不同的方式定義類型。 C++本來只不過是C上的一個附加集合。
幾乎所有C/C++開發人員今天都有這樣的問題:a)大學不再教授基礎知識,b)人們不理解定義和聲明之間的區別。
此類聲明和定義存在的唯一原因是,鏈接器可以計算結構中字段的地址偏移量。這就是爲什麼大多數人擺脫了實際寫入不正確的代碼 - 因爲編譯器能夠確定尋址。當有人試圖進行某些事情時會出現問題,例如隊列或鏈接列表,或者支持O/S結構。
聲明以'struct'開頭,定義以'typedef'開始。
另外,結構體具有前向聲明標籤和定義的標籤。大多數人不知道這一點,並使用前向聲明標籤作爲定義標籤。
錯誤:
struct myStruct
{
int field_1;
...
};
他們只需要使用向前聲明標註的結構 - 所以現在的編譯器知道它 - 但它不是一個實際的定義類型。編譯器可以計算尋址 - 但這不是它打算如何使用的原因,因爲我將暫時顯示。
使用這種形式的聲明的人必須在實際上每次引用它時都必須使用「struct」 - 因爲它不是一種官方的新類型。
相反,不引用本身的任何結構,應該聲明和定義只有這樣:
typedef struct
{
field_1;
...
}myStruct;
現在,它是一個真正的類型,使用的時候可以在爲「MYSTRUCT」使用,而不必用「結構」這個詞加上它。
如果你想有一個指針變量到結構,則包括二次標籤:
typedef struct
{
field_1;
...
}myStruct,*myStructP;
現在你有一個指針變量到結構,習慣它。
FORWARD DECLARATION--
現在,這裏的花哨的東西,向前聲明是如何工作的。如果你想創建一個引用自身的類型,比如鏈接列表或者隊列元素,你必須使用前向聲明。編譯器不考慮定義的結構,直到它到達最後的分號,所以它只是在該點之前聲明。現在
typedef struct myStructElement
{
myStructElement* nextSE;
field_1;
...
}myStruct;
,編譯器知道,雖然它不知道整個類型是什麼呢,它仍然可以使用向前參考引用它。
請正確聲明和typedef你的結構。其實有一個原因。
我不相信C++曾經是「一系列包含在C之上的東西」。第一個實現是cfront,它是一個將C++源代碼翻譯爲C源代碼的預處理器。我不同意你對結構使用typedefs的建議,特別是針對指針。在typedef後面隱藏指針類型可能很危險;它更好的恕我直言,使事實,這是一個指針明確使用'*'。在你最後的例子中,我很好奇使用typedef的一個名字('myStruct')和struct標籤的另一個名字('myStructElement')。 – 2016-05-07 21:44:22
這很大程度上是一個文體偏好問題。我對你的大部分建議(這並不是說你錯了)相當不滿。請參閱[我的答案](http://stackoverflow.com/a/26389105/827263),瞭解我自己的偏好摘要(許多C程序員都共享這些偏好,但當然不是全部)。 – 2016-05-07 21:45:22
我剛剛在這裏閱讀,第二個選項會給編譯器錯誤?! 「傳遞不兼容的指針類型的參數」http://stackoverflow.com/questions/12708897/typedefs-struct-tag-and-alias – hewi 2015-12-18 16:10:08