简体   繁体   English

什么是“前向声明”以及“ typedef struct X”和“ struct X”之间的区别?

[英]What is 'forward declaration' and the difference between 'typedef struct X' and 'struct X'?

I am a beginner in C programming and I know the difference between struct type declaration and typedef struct declaration. 我是C编程的初学者,我知道struct类型声明和typedef结构声明之间的区别。 I came across to know an answer saying that if we define a struct like: 我碰到一个答案,说如果我们定义一个struct如:

typedef struct { 
    some members;
} struct_name;

Then it will be like providing an alias to an anonymous struct (as it is not having a tag name). 然后就像为匿名结构提供别名(因为它没有标签名称)。 So it can't be used for forward declaration. 因此,它不能用于前向声明。 I don't know what the forward declaration means. 我不知道向前声明的意思。

Also, I wanted to know that for the following code: 另外,我想知道以下代码:

typedef struct NAME { 
    some members;
} struct_alias;

Is there any difference between NAME and struct_alias ? NAMEstruct_alias有什么区别? Or are both equal as struct_alias is an alias of struct NAME ? 还是两者都相等,因为struct_alias是struct NAME的别名?

Furthermore, can we declare a variable of type struct NAME like these: 此外,我们可以这样声明一个类型为struct NAME的变量struct NAME

struct_alias variable1;

and/or like: 和/或类似:

struct NAME variable2;

or like: 或类似:

NAME variable3; 

struct forward declarations can be useful when you need to have looping struct declarations. 当需要循环结构声明时, struct前向声明会很有用。 Example: 例:

struct a {
    struct b * b_pointer;
    int c;
};

struct b {
    struct a * a_pointer;
    void * d;
};

When struct a is declared it doesn't know the specs of struct b yet, but you can forward reference it. 声明struct a时,尚不知道struct b的规格,但您可以转发引用它。

When you typedef an anonymous struct then the compiler won't allow you to use it's name before the typedef. 当您对匿名结构进行类型定义时,编译器将不允许您在类型定义之前使用其名称。

This is illegal: 这是非法的:

struct a {
    b * b_pointer;
    int c;
};

typedef struct {
    struct a * a_pointer;
    void * d;
} b;

// struct b was never declared or defined

This though is legal: 这是合法的:

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

So is this: 这是这样的:

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;
};

And this (only in C, illegal in C++): 这(仅在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++

Forward declaration is a promise to define something that you make to a compiler at the point where the definition cannot be made. 前向声明是一种承诺,可以在无法进行定义的时候定义您对编译器所做的事情。 The compiler can use your word to interpret other declarations that it would not be able to interpret otherwise. 编译器可以使用您的单词来解释其他无法解释的声明。

A common example is a struct designed to be a node in a linked list: you need to put a pointer to a node into the struct , but the compiler would not let you do it without either a forward declaration or a tag: 一个常见的示例是一个struct ,该struct设计为链接列表中的一个节点:您需要在该struct放置一个指向节点的指针,但是如果没有前向声明或标记,编译器将不允许您这样做:

// Forward declaration
struct element;
typedef struct {
    int value;
    // Use of the forward declaration
    struct element *next;
} element; // Complete definition

and so it cant be used for forward declaration 所以它不能用于前向声明

I think that author's point was that giving your struct a tag would be equivalent to a forward declaration: 我认为作者的观点是给您的struct一个标签将等同于一个前向声明:

typedef struct element {
    int value;
    // No need for a forward declaration here
    struct element *next;
} element;

Forward declaration is a declaration preceeding an actual definition, usually for the purpose of being able to reference the declared type when the definition is not available. 前向声明是在实际定义之前的声明,通常是为了在该定义不可用时能够引用已声明的类型。 Of course, not everything may be done with the declared-not-defined structure, but in certain context it is possible to use it. 当然,不是所有的事情都可以使用声明的未定义结构来完成,但是在某些情况下可以使用它。 Such type is called incomplete , and there are a number of restrictions on its usage. 这种类型称为不完整类型,其使用受到许多限制。 For example: 例如:

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 { /* ... */ };

This can be useful eg to break circular dependencies, or cut down the compilation time, as the definitions are usually significantly larger, and so more resources are required to parse it. 这可能很有用,例如打破循环依赖关系或减少编译时间,因为定义通常要大得多,因此需要更多资源来解析它。

In your example, struct NAME and struct_alias are indeed equivalent. 在您的示例中, struct NAMEstruct_alias实际上是等效的。

struct_alias variable1;
struct NAME variable2;

are correct; 是正确的;

NAME variable3;

is not, as in C the struct keyword is required. 不是,因为在C中, struct关键字是必需的。

struct_alias and struct NAME are same , struct_alias is an alias to struct NAME struct_aliasstruct NAME相同, struct_aliasstruct NAME的别名

These both are same and allowed 这两者是相同的,并且允许

struct_alias variable1;  

struct NAME variable1; 

this is illegal 这是非法的

NAME variable3;   

See this article on Forward declaration 请参阅有关前向声明的文章

As others stated before, a forward declaration in C/C++ is the declaration of something with the actual definition unavailable. 如前所述,C / C ++中的前向声明是对实际定义不可用的内容的声明。 Its a declaration telling the compiler "there is a data type ABC". 它的声明告诉编译器“存在数据类型ABC”。

Lets pretend this is a header for some key/value store my_dict.h : 让我们假装这是一些键/值存储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);
...

You dont know anything about my_dict_t , but actually, for using the store you dont need to know: 您对my_dict_t ,但是实际上,使用商店不需要知道:

#include "my_dict.h"
...
struct my_dict_t* dict = create();
if(0 != insert(dict, "AnEntry", strdup("AValue"))) {
    ...
}
...

The reason for this is: You are only using POINTERS to the data structure. 原因是:您仅对数据结构使用POINTERS。

POINTERS are just numbers, and for dealing with them you dont need to know what they are pointing at. 指针只是数字,与它们打交道时,您无需知道它们的指向。

This will only matter if you try to actually access them, like 这仅在您尝试实际访问它们时才有意义,例如

struct my_dict_t* dict = create();
printf("%s\n", dict->value);  /* Impossible if only a forward decl is available */

So, for implementing the functions, you require an actual definition of my_struct_t . 因此,为了实现这些功能,您需要一个实际的my_struct_t定义。 You might do this in the source file my_dict.c like so: 您可以这样在源文件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));
}

This is handy for several situations, like 这在几种情况下都很方便,例如

  • For resolving circular type dependencies, like Sergei L. explained. 对于解析循环类型的依赖关系,如Sergei L.所述。
  • For encapsulation, like in the example above. 对于封装,如上例所示。

So the question that remains is: Why cant we just omit the forward declaration at all when using the functions above? 所以剩下的问题是:为什么在使用上述函数时我们根本不能完全省略前向声明? In the end, it would suffice for the compiler to know that all dict are pointers. 最后,编译器知道所有dict都是指针就足够了。

However, the compiler does perform type checks: It needs to verify that you don't do something like 但是,编译器会执行类型检查:它需要验证您没有执行类似的操作

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

It does not need to know how my_dict_t looks like, but it needs to know that &i is not the type of pointer get_value() expects. 它不需要知道my_dict_t样子,但是需要知道&i不是get_value()指针的类型。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM