![](/img/trans.png)
[英]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.