我正在尝试typedef
一个struct
,其中包含指向另一个相同类型的指针。
这就是我认为最好的版本:
typedef struct Element
{
char value;
struct Element *next;
} Element;
为什么该变体也在编译+执行?:
typedef struct
{
char value;
struct Element *next;
} Element;
要描述第一个我要说的:“名称struct Element
Element
现在”,第二个名称为:“请匿名struct
并称之为Element
“
但为什么我仍然可以在第二种情况下声明struct Element
(在结构内)?
(使用GCC
和MSVC
)
答案 0 :(得分:22)
在第一种情况下,您的结构有两个等效名称:struct Element
(其中Element
是结构标记)和Element
(其中Element
是typedef,现有类型的别名。)
在第二种情况下,您只是没有为结构定义标记。通常情况下这是完全有效的,但在这里你指的是struct Element
成员声明中不存在的类型next
。
在该上下文中,struct Element
是不完整类型。您不能声明不完整类型的对象,但可以声明指向它们的指针。
声明
typedef struct
{
char value;
struct Element *next;
} Element;
是合法的,但它不会使next
指向封闭类型。它使它成为指向某些不完整类型的指针,除非您声明完整类型,否则您将无法引用它。
你的第二个宣言是过多的没有意义的事情之一,但仍然是合法的C.
您可能会考虑省略typedef并始终将类型称为struct Element
。很多人都喜欢为结构类型设置单字名称的便利,但我个人的意见是,没有太多的好处(除非类型真的不透明,即类型的用户甚至不知道它是一个结构)。这是一种风格问题。
请注意,您需要在定义中引用类型struct Element
,而不是Element
,因为typedef名称Element
尚未显示。
struct标签和typedef具有相同名称的事实可能看起来令人困惑,但它完全合法。 struct标签和typedef位于不同的命名空间中(在C意义上,而不是C ++意义上);结构标记只能在struct
关键字后立即显示。
另一种方法是将typedef与struct定义分开:
typedef struct Element Element;
struct Element {
char value;
Element *next;
};
(您可以在typedef
中使用不完整的类型名称。)
答案 1 :(得分:4)
你的第一个变种是正确的。你的第二个版本没有做它看起来做的事情。
在C中,即使在声明其他内容的情况下,也可以将结构类型转发到任何地方。 (此类声明的范围规则令我感到困惑,我不打算解释它们 - 足以说明你应该避免这样做。)这就是为什么你没有得到错误在第二个结构上。但它对编译器的意味着是这样的:
struct _Anonymous_1 // name not actually accessible to code
{
char value;
struct Element *next;
};
typedef struct _Anonymous_1 Element;
在此代码之后,“struct Element”类型与“Element”类型完全无关,并且尚未完全声明。如果您尝试使用该类型,例如在
char cadr(Element *cons)
{
return cons->next->value;
}
编译器不高兴:
test.c: In function ‘cadr’:
test.c:9:22: error: dereferencing pointer to incomplete type
您的第一个变体的替代方案,它允许您在任何地方使用“元素”而不是“结构元素”,包括在类型的定义内,是
typedef struct Element Element;
struct Element
{
char value;
Element *next;
};
但在C语言中,没有办法避免必须手动确保“struct Element”与“Element”相同。如果您不想处理它,那么C ++就在那里等着你⟶
答案 2 :(得分:0)
要存储指向结构的指针,编译器不需要知道其内容或大小 - 只需指向指针的大小。
在你的第一个例子中,struct Element
是一个不完整的类型,直到结构定义之后,但这是有效的,因为你只是声明指向它的指针,而不是结构本身的实例。
在第二个示例中,您根本没有声明struct Element
结构(struct Element
和Element
不是一回事)。虽然您仍然可以在结构中包含指针,但它不引用相同的类型,它指的是尚未定义的struct Element
。 typedef中的struct定义是一个匿名结构,因此您只能使用Element
(不带struct关键字)来引用它。所以第二个例子不会按预期工作。