[英]Why is “typedef struct foo foo;” considered harmful?
在C 與 C++ 中的 typedef 和 struct 命名空間中,其中一條注釋似乎暗示暴露一些struct foo
比使用 typedef 更可取...
typedef struct foo foo;
...然后在整個 API 中使用foo
而不是struct foo
。
后一種變體有什么缺點嗎?
唯一的缺點 (*) 是它隱藏了foo
是結構體而不是某些內置類型的別名的事實。
注意(*):這是否對您不利是品味問題。
這取決於您有多喜歡struct
一詞。 如果您覺得通過struct tother
struct that
和struct tother
您的程序更加清晰(當然,您不能在 C++ 中使用struct this
),那么請struct tother
使用struct
版本。
就我個人而言,我認為重復struct
沒有任何好處,我很高興只使用typedef
名稱。 並且因為 C++ 有效地提供了typedef struct xyz xyz;
自動聲明(它不太准確,尤其是因為您可以在 C++ 中明確地編寫它,但它足夠接近,您可能不必擔心),我認為在C. C 編譯器對它很滿意,所以我通常使用typedef struct tag tag;
然后在需要的地方使用tag
和tag *
。
對於另一種但完全站得住腳的觀點,請閱讀Linux 內核編碼風格指南。
請注意,C2011 允許您重新定義typedef
,只要它具有相同類型的別名:
ISO/IEC 9899:2011 §6.7 聲明
語義
¶5 聲明指定了一組標識符的解釋和屬性。 標識符的定義是對該標識符的聲明:
— 對於一個對象,導致為該對象保留存儲空間;
——對於函數,包括函數體; 119)
— 對於枚舉常量,是標識符的(唯一)聲明;
— 對於 typedef 名稱,是標識符的第一個(或唯一)聲明。
與 C99 相比,這是不可能的:
語義
¶5 聲明指定了一組標識符的解釋和屬性。 標識符的定義是對該標識符的聲明:
— 對於一個對象,導致為該對象保留存儲空間;
——對於函數,包括函數體; 98)
— 對於枚舉常量或 typedef 名稱,是標識符的(唯一)聲明。
只要您保持一致(但前提是您在與您相關的每個平台上都有足夠兼容的 C2011 編譯器),這會簡化類型定義的創建。
關於是否要 typedef 結構類型:
以下是一些意見(都反對 typedefing 結構):
來自 OpenBSD 風格指南:
“避免對結構類型使用 typedef。這使得應用程序不可能不透明地使用指向這種結構的指針,這在使用普通結構標記時既可能又有益。”
來自 Linux 內核編碼風格:
“將 typedef 用於結構和指針是錯誤的。”
來自 Peter Van der Linden 的 Expert C Programming:
“不要為結構體的 typedef 煩惱。他們所做的只是讓你不用寫“結構體”這個詞,這是一個你可能不應該隱藏的線索。”
這或多或少是品味問題。
通過聲明一個struct
標簽,該名稱也可用於同一范圍內的變量、函數或枚舉數(或者甚至是另一種類型,如果你喜歡混淆); 並且用戶必須編寫單詞struct
,這使他們的代碼更加明確。
通過同時聲明類型名稱,您可以允許人們在他們不想時不要輸入struct
。
我在另一個問題中的評論是指與結構標記同名的指針類型的聲明:
typedef struct foo * foo;
在風格上,這有點令人不快,因為它隱藏了它是一個指針的事實。 這隱藏了它是一個指針的事實; 在該問題的上下文中,這可能沒問題,這是由 API 定義的不透明類型,但在我看來,對於非不透明類型來說,這將是相當粗魯的。 它還破壞了與 C++ 的兼容性。 在該語言中,這樣的聲明是無效的,因為struct foo
將foo
引入當前命名空間而不是單獨的標記空間,並防止在該命名空間中聲明任何其他具有相同名稱的類型。
只要堅持命名約定,你就會沒事的。
typedef struct
{
//...
} t_mytype;
//...
t_mytype thing;
這樣你就會知道它是一個自定義類型。 至於它是一個結構,只需使用顯式名稱而不是真正的t_mytype
另一個反對 typedef 的論點是它編寫干凈的標頭的難度。 讓我們看一個標題的例子:
#ifndef HEADER_H
#define HEADER_H
#include "s.h"
void f(struct s *);
#endif
這個標題可以改進。 實際上, struct s
不需要定義。 所以可以寫成:
#ifndef HEADER_H
#define HEADER_H
struct s;
void f(struct s *);
#endif
因此,用戶可以使用struct s
作為一個不透明的結構,我們可以保持"sh"
私有。
讓我們用typedef
做同樣的事情:
#ifndef HEADER_H
#define HEADER_H
typedef struct s s_t;
void f(s_t *);
#endif
行typedef struct s s_t
將出現在每個想要使用s_t *
標題中,我不喜歡冗余代碼。 有多種方法可以避免這種情況,但最簡單的方法可能是擺脫 typedef。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.