簡體   English   中英

什么是“前向聲明”以及“ typedef struct X”和“ 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;

NAMEstruct_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 NAMEstruct_alias實際上是等效的。

struct_alias variable1;
struct NAME variable2;

是正確的;

NAME variable3;

不是,因為在C中, struct關鍵字是必需的。

struct_aliasstruct NAME相同, struct_aliasstruct 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));
}

這在幾種情況下都很方便,例如

  • 對於解析循環類型的依賴關系,如Sergei L.所述。
  • 對於封裝,如上例所示。

所以剩下的問題是:為什么在使用上述函數時我們根本不能完全省略前向聲明? 最后,編譯器知道所有dict都是指針就足夠了。

但是,編譯器會執行類型檢查:它需要驗證您沒有執行類似的操作

...
int i = 12;
char* value = get_value(&i, "MyName");
...

它不需要知道my_dict_t樣子,但是需要知道&i不是get_value()指針的類型。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

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