[英]What's the difference between `typedef struct X { }` and `typedef struct { } X`?
[英]What is 'forward declaration' and the difference between 'typedef struct X' and 'struct X'?
我是C編程的初學者,我知道struct
類型聲明和typedef
結構聲明之間的區別。 我碰到一個答案,說如果我們定義一個struct
如:
typedef struct {
some members;
} struct_name;
然后就像為匿名結構提供別名(因為它沒有標簽名稱)。 因此,它不能用於前向聲明。 我不知道向前聲明的意思。
另外,我想知道以下代碼:
typedef struct NAME {
some members;
} struct_alias;
NAME
和struct_alias
有什么區別? 還是兩者都相等,因為struct_alias
是struct NAME的別名?
此外,我們可以這樣聲明一個類型為struct NAME
的變量struct NAME
:
struct_alias variable1;
和/或類似:
struct NAME variable2;
或類似:
NAME variable3;
當需要循環結構聲明時, struct
前向聲明會很有用。 例:
struct a {
struct b * b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
聲明struct a
時,尚不知道struct b
的規格,但您可以轉發引用它。
當您對匿名結構進行類型定義時,編譯器將不允許您在類型定義之前使用其名稱。
這是非法的:
struct a {
b * b_pointer;
int c;
};
typedef struct {
struct a * a_pointer;
void * d;
} b;
// struct b was never declared or defined
這是合法的:
struct a {
struct b * b_pointer;
int c;
};
typedef struct b {
struct a * a_pointer;
void * d;
} b;
// struct b is defined and has an alias type called b
這是這樣的:
typedef struct b b;
// the type b referes to a yet undefined type struct b
struct a {
b * struct_b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
這(僅在C中,在C ++中是非法的):
typedef int b;
struct a {
struct b * struct_b_pointer;
b b_integer_type;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
// struct b and b are two different types all together. Note: this is not allowed in C++
前向聲明是一種承諾,可以在無法進行定義的時候定義您對編譯器所做的事情。 編譯器可以使用您的單詞來解釋其他無法解釋的聲明。
一個常見的示例是一個struct
,該struct
設計為鏈接列表中的一個節點:您需要在該struct
放置一個指向節點的指針,但是如果沒有前向聲明或標記,編譯器將不允許您這樣做:
// Forward declaration
struct element;
typedef struct {
int value;
// Use of the forward declaration
struct element *next;
} element; // Complete definition
所以它不能用於前向聲明
我認為作者的觀點是給您的struct
一個標簽將等同於一個前向聲明:
typedef struct element {
int value;
// No need for a forward declaration here
struct element *next;
} element;
前向聲明是在實際定義之前的聲明,通常是為了在該定義不可用時能夠引用已聲明的類型。 當然,不是所有的事情都可以使用聲明的未定義結構來完成,但是在某些情況下可以使用它。 這種類型稱為不完整類型,其使用受到許多限制。 例如:
struct X; // forward declaration
void f(struct X*) { } // usage of the declared, undefined structure
// void f(struct X) { } // ILLEGAL
// struct X x; // ILLEGAL
// int n =sizeof(struct X); // ILLEGAL
// later, or somewhere else altogether
struct X { /* ... */ };
這可能很有用,例如打破循環依賴關系或減少編譯時間,因為定義通常要大得多,因此需要更多資源來解析它。
在您的示例中, struct NAME
和struct_alias
實際上是等效的。
struct_alias variable1;
struct NAME variable2;
是正確的;
NAME variable3;
不是,因為在C中, struct
關鍵字是必需的。
struct_alias
和struct NAME
相同, struct_alias
是struct NAME
的別名
這兩者是相同的,並且允許
struct_alias variable1;
struct NAME variable1;
這是非法的
NAME variable3;
請參閱有關前向聲明的文章
如前所述,C / C ++中的前向聲明是對實際定義不可用的內容的聲明。 它的聲明告訴編譯器“存在數據類型ABC”。
讓我們假裝這是一些鍵/值存儲my_dict.h
的標頭:
...
struct my_dict_t;
struct my_dict_t* create();
char* get_value(const struct my_dict_t* dict, const char* name);
char* insert(struct my_dict_t* dict, const char* name, char* value);
void destroy(struct my_dict_t* dict);
...
您對my_dict_t
,但是實際上,使用商店不需要知道:
#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
...
}
...
原因是:您僅對數據結構使用POINTERS。
指針只是數字,與它們打交道時,您無需知道它們的指向。
這僅在您嘗試實際訪問它們時才有意義,例如
struct my_dict_t* dict = create();
printf("%s\n", dict->value); /* Impossible if only a forward decl is available */
因此,為了實現這些功能,您需要一個實際的my_struct_t
定義。 您可以這樣在源文件my_dict.c
執行此操作:
#include "my_dict.h"
struct my_dict_t {
char* value;
const char* name;
struct my_dict_t* next;
}
struct my_dict_t* create() {
return calloc(1, sizeof(struct my_dict_t));
}
這在幾種情況下都很方便,例如
所以剩下的問題是:為什么在使用上述函數時我們根本不能完全省略前向聲明? 最后,編譯器知道所有dict
都是指針就足夠了。
但是,編譯器會執行類型檢查:它需要驗證您沒有執行類似的操作
...
int i = 12;
char* value = get_value(&i, "MyName");
...
它不需要知道my_dict_t
樣子,但是需要知道&i
不是get_value()
指針的類型。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.