繁体   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