簡體   English   中英

為什么是“typedef struct foo foo;” 認為有害?

[英]Why is “typedef struct foo foo;” considered harmful?

C 與 C++ 中的 typedef 和 struct 命名空間中,其中一條注釋似乎暗示暴露一些struct foo比使用 typedef 更可取...

typedef struct foo foo;

...然后在整個 API 中使用foo而不是struct foo

后一種變體有什么缺點嗎?

唯一的缺點 (*) 是它隱藏了foo是結構體而不是某些內置類型的別名的事實。

注意(*):這是否對您不利是品味問題。

  • 這有利於完全不透明(請參閱下面的第一條評論)。
  • 要了解為什么有些人認為這是一個缺點,請查看linux 內核編碼風格(typedefs 章節)。

這取決於您有多喜歡struct一詞。 如果您覺得通過struct tother struct thatstruct tother您的程序更加清晰(當然,您不能在 C++ 中使用struct this ),那么請struct tother使用struct版本。

就我個人而言,我認為重復struct沒有任何好處,我很高興只使用typedef名稱。 並且因為 C++ 有效地提供了typedef struct xyz xyz; 自動聲明(它不太准確,尤其是因為您可以在 C++ 中明確地編寫它,但它足夠接近,您可能不必擔心),我認為在C. C 編譯器對它很滿意,所以我通常使用typedef struct tag tag; 然后在需要的地方使用tagtag *


對於另一種但完全站得住腳的觀點,請閱讀Linux 內核編碼風格指南。


請注意,C2011 允許您重新定義typedef ,只要它具有相同類型的別名:

ISO/IEC 9899:2011 §6.7 聲明

語義

¶5 聲明指定了一組標識符的解釋和屬性。 標識符的定義是對該標識符的聲明:

— 對於一個對象,導致為該對象保留存儲空間;

——對於函數,包括函數體; 119)

— 對於枚舉常量,是標識符的(唯一)聲明;

— 對於 typedef 名稱,是標識符的第一個(或唯一)聲明。

與 C99 相比,這是不可能的:

ISO/IEC 9899:1999 §6.7 聲明

語義

¶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 foofoo引入當前命名空間而不是單獨的標記空間,並防止在該命名空間中聲明任何其他具有相同名稱的類型。

只要堅持命名約定,你就會沒事的。

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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM