[英]Difference of typedef before or after block in decleration/definition with or without a pointer, with or without a list?
每種風格的優勢是什么? 包含指針如何改變事物?
一個在標簽之前,另一個在 object 標識符之前。 Typedef 建立在它們的前身之上,這些前輩最終源自一些原始類型安排。
clang 可接受以下內容:
typedef struct typeA {int i;} typeA;
struct typeB {int i;} typedef typeB;
typedef struct typeAa {int i;} * typeAa;
struct typeBb {int i;} typedef * typeBb;
typedef struct typeC {} typeC;
struct typeD {} typedef typeD;
typedef struct typeCc {} * typeCc;
struct typeDd {} typedef * typeDd;
typedef struct typeE {} typeE, typeEptr[], * typeEArrayptr, typeEptrArrayfunc();
謝謝!
在搜索前后無法在 [c][typedef][structs] 中找到任何結果,這就是全部結果:
問題包含代碼:
typedef struct typeA {int i;} typeA;
struct typeB {int i;} typedef typeB;
typedef struct typeAa {int i;} * typeAa;
struct typeBb {int i;} typedef * typeBb;
typedef struct typeC {} typeC;
struct typeD {} typedef typeD;
typedef struct typeCc {} * typeCc;
struct typeDd {} typedef * typeDd;
typedef struct typeE {} typeE, typeEptr[], * typeEArrayptr, typeEptrArrayfunc();
據稱clang
接受了它。 在某種程度上,這是准確的:如果沒有指定警告選項,GCC 和clang
都會毫無怨言地接受代碼。 添加一組相當全面的警告選項,你會得到很多錯誤:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes -pedantic --pedantic-errors -c td17.c
td17.c:4:12: error: ‘typedef’ is not at beginning of declaration [-Werror=old-style-declaration]
4 | struct typeB {int i;} typedef typeB;
| ^~~~~
td17.c:7:12: error: ‘typedef’ is not at beginning of declaration [-Werror=old-style-declaration]
7 | struct typeBb {int i;} typedef * typeBb;
| ^~~~~~
td17.c:9:20: error: struct has no members [-Wpedantic]
9 | typedef struct typeC {} typeC;
| ^~~~~
td17.c:10:12: error: struct has no members [-Wpedantic]
10 | struct typeD {} typedef typeD;
| ^~~~~
td17.c:10:12: error: ‘typedef’ is not at beginning of declaration [-Werror=old-style-declaration]
td17.c:11:20: error: struct has no members [-Wpedantic]
11 | typedef struct typeCc {} * typeCc;
| ^~~~~~
td17.c:12:12: error: struct has no members [-Wpedantic]
12 | struct typeDd {} typedef * typeDd;
| ^~~~~~
td17.c:12:12: error: ‘typedef’ is not at beginning of declaration [-Werror=old-style-declaration]
td17.c:14:20: error: struct has no members [-Wpedantic]
14 | typedef struct typeE {} typeE, typeEptr[], * typeEArrayptr, typeEptrArrayfunc();
| ^~~~~
td17.c:14:20: error: function declaration isn’t a prototype [-Werror=strict-prototypes]
cc1: all warnings being treated as errors
$
在 C 語法中, typedef
被視為存儲 class — 就像extern
、 static
等 — 盡管還有一個專門針對typedef
的部分。 還有一個未來方向§6.11.5 存儲 class 說明符,其中指出:
除了在聲明中的聲明說明符的開頭之外,存儲類說明符的放置是一個過時的功能。
因此,在您的問題中, typedef
出現在聲明中的第一個單詞之外的每個變體都使用了 C 的過時功能,不應在新代碼中使用。 它仍然支持向后兼容,而不是因為它應該被使用。
有一個 Q&A Is it a good idea to typedef pointers? 大多數人的觀點是答案是“否——function 指針可能是個例外”。
空結構定義typedef struct typeC {} typeC;
違反§6.7.2.1 結構和聯合說明符的規則,特別是 ¶8 其中說:
…如果結構聲明列表不包含任何命名成員,無論是直接還是通過匿名結構或匿名聯合,行為是未定義的。 ……
因此,空括號會調用未定義的行為。 然而,除非它們受到迂腐選項的約束,否則編譯器決定他們將接受該聲明,即使它沒有由標准 C 定義。如此定義的結構類型幾乎沒有用。 由於{}
,類型是完整的,但為空。 事實上,如果您打印sizeof(typeC)
或等效值(沒有警告選項),那么打印的結果是0
。 您可以使用指向類型的指針,但不能使用類型。
考慮對初始代碼的擴展:
#include <stdio.h>
typedef struct typeF
{
size_t size;
struct typeC C;
size_t left;
} typeF;
int main(void)
{
printf("sizeof(typeC) = %zu\n", sizeof(typeC));
printf("sizeof(typeF) = %zu\n", sizeof(typeF));
printf("offsetof(typeF, C) = %zu\n", offsetof(typeF, C));
printf("offsetof(typeF, left) = %zu\n", offsetof(typeF, left));
return 0;
}
在 64 位機器上,output 是:
sizeof(typeC) = 0
sizeof(typeF) = 16
offsetof(typeF, C) = 8
offsetof(typeF, left) = 8
請注意,Linux kernel 編碼標准不允許對結構使用typedef 。 所有結構都必須有一個標簽,並且在引用類型時必須始終使用struct tag
。
另一種觀點是,您始終對結構類型使用 typedef 名稱。 在簡單的情況下,這意味着您可以使用:
typedef struct
{
int number;
char *name;
} NumberName;
但是,如果您需要自引用指針(例如,對於鏈表),則該結構必須有一個標記。 您可以使用以下順序:
typedef struct SomeTag SomeTag;
struct SomeTag
{
int number;
char *name;
SomeTag *next;
SomeTag *prev;
};
使用這種形式,您只能使用SomeTag
來引用這種類型。 如果您在某處編寫struct SomeTag
,它不會引用顯示的類型。 它可能引用在別處定義的不完整類型,但更可能是錯誤。
或者,您可以使用:
typedef struct SomeTag
{
int number;
char *name;
struct SomeTag *next;
struct SomeTag *prev;
} SomeTag;
使用這種形式,在 typedef 定義之后,您可以使用SomeTag
或struct SomeTag
來引用結構類型。 但是,由於在定義結構體時沒有引入typedef名稱,所以必須在結構體內部使用符號struct SomeTag *
。
雖然這不是強制性的,但為標記和 typedef 名稱使用相同的名稱是相當常規的。 沒有沖突; 它們位於不同的命名空間中(§6.2.3 標識符的名稱空間。C++ 自動提供 class 或類型名稱,當您定義 class、結構或聯合時,不帶class
、 struct
或union
前綴,因此對兩者使用相同的標記是一致的與 C++。還有其他學派認為標簽名稱應該與類型名稱不同。一個這樣的約定是typedef struct SomeTag_s SomeTag_t;
(使用不同的后綴)。注意 POSIX 保留_t
后綴(參見§2.2 The編譯環境和§2.2.2 名稱空間——尤其是“任何標頭”保留后綴_t
的那一行)。
請注意,function 指針聲明typeEptrArrayFunc()
等效於:
struct typeE typeEptrArrayfunc();
這聲明了一個 function 類型,它返回一個struct typeE
並采用一個不確定的參數列表(但它不是一個可變參數 function 類型,在原型的末尾帶有, ...
)。 它不是 C90 到 C17/C18 中的嚴格原型。 在 C23 中,它將等同於:
struct typeE typeEptrArrayfunc(void);
這是一個 function 類型,沒有 arguments。
類型typeEptrArrayfunc
與指針或 arrays 無關,盡管名稱如此。 類似的注釋適用於typeEArrayptr
— 該類型是“指向struct typeE
的指針”,與 arrays 無關。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.