C语言 什么是“前向声明”以及“typedef struct X”和“struct X”之间的区别?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18658438/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is 'forward declaration' and the difference between 'typedef struct X' and 'struct X'?
提问by r_goyal
I am a beginner in C programming and I know the difference between structtype declaration and typedefstruct declaration. I came across to know an answer saying that if we define a structlike:
我是 C 编程的初学者,我知道struct类型声明和typedef结构声明之间的区别。我偶然知道一个答案说,如果我们定义一个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 declarationmeans.
然后就像为匿名结构提供别名(因为它没有标签名称)。所以它不能用于前向声明。我不知道前向声明是什么意思。
Also, I wanted to know that for the following code:
另外,我想知道以下代码:
typedef struct NAME {
some members;
} struct_alias;
Is there any difference between NAMEand struct_alias? Or are both equal as
struct_aliasis an alias of struct NAME ?
有什么区别NAME和struct_alias?或者两者都struct_alias与 struct NAME 的别名相同
?
Furthermore, can we declare a variable of type struct NAMElike these:
此外,我们可以声明一个struct NAME这样类型的变量:
struct_alias variable1;
and/or like:
和/或喜欢:
struct NAME variable2;
or like:
或喜欢:
NAME variable3;
回答by Sergey L.
structforward declarations can be useful when you need to have looping struct declarations. Example:
struct当您需要循环结构声明时,前向声明会很有用。例子:
struct a {
struct b * b_pointer;
int c;
};
struct b {
struct a * a_pointer;
void * d;
};
When struct ais declared it doesn't know the specs of struct byet, 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.
当您 typedef 一个匿名结构时,编译器将不允许您在 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++
回答by dasblinkenlight
Forward declarationis 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 structdesigned 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:
一个常见的例子是 a 被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 structa 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;
回答by Marcin ?o?
Forward declarationis 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 e.g. 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 NAMEand struct_aliasare indeed equivalent.
在你的例子中,struct NAME和struct_alias确实是等价的。
struct_alias variable1;
struct NAME variable2;
are correct;
是正确的;
NAME variable3;
is not, as in C the structkeyword is required.
不是,因为在 Cstruct中需要关键字。
回答by Gangadhar
struct_aliasand struct NAMEare same ,struct_aliasis an alias to struct NAME
struct_alias并且struct NAME是相同的,struct_alias是一个别名struct NAME
These both are same and allowed
这些都是相同的并且是允许的
struct_alias variable1;
struct NAME variable1;
this is illegal
这是非法的
NAME variable3;
See this article on Forward declaration
请参阅有关前向声明的这篇文章
回答by Michael Beer
As others stated before, a forward declaration in C/C++ is the declaration of something with the actual definition unavailable. Its a declaration telling the compiler "there is a data type ABC".
正如其他人之前所说的,C/C++ 中的前向声明是实际定义不可用的声明。它是一个声明,告诉编译器“有一个数据类型 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.
You might do this in the source file my_dict.clike so:
因此,为了实现这些功能,您需要实际定义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));
}
This is handy for several situations, like
这在几种情况下都很方便,比如
- For resolving circular type dependencies, like Sergei L. explained.
- For encapsulation, like in the example above.
- 用于解决循环类型的依赖关系,就像 Sergei L. 解释的那样。
- 对于封装,就像上面的例子一样。
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 dictare 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_tlooks like, but it needs to know that &iis not the type of pointer get_value()expects.
它不需要知道my_dict_t看起来像什么,但它需要知道这&i不是指针所get_value()期望的类型。

