“为什么?”;typdef struct{struct S*S;}S&引用;是否包含指向同一类型的指针?

“为什么?”;typdef struct{struct S*S;}S&引用;是否包含指向同一类型的指针?,c,struct,typedef,C,Struct,Typedef,我正在尝试typedefastruct,其中包含指向另一个相同类型的指针 这是我认为最好的版本: 为什么该变体也在编译+执行 为了描述第一个,我会说:“现在命名struct元素Element”,第二个是:“把这个匿名struct称为Element” 但是为什么在第二种情况下我仍然可以声明一个结构元素(在结构内部) (在GCC和MSVC中工作)在第一种情况下,您的结构有两个等效名称:struct Element(其中Element是结构标记)和Element(其中Element是typedef,是

我正在尝试
typedef
a
struct
,其中包含指向另一个相同类型的指针

这是我认为最好的版本:

为什么该变体也在编译+执行

为了描述第一个,我会说:“现在命名
struct元素
Element
”,第二个是:“把这个匿名
struct
称为
Element

但是为什么在第二种情况下我仍然可以声明一个
结构元素(在结构内部)


(在
GCC
MSVC
中工作)

在第一种情况下,您的结构有两个等效名称:
struct Element
(其中
Element
是结构标记)和
Element
(其中
Element
是typedef,是现有类型的别名)

在第二种情况下,您只是没有为结构定义标记。通常情况下,这是完全有效的,但在这里,您指的是
下一个
成员声明中不存在的类型
struct元素

在这种情况下,
struct元素
是一种不完整的类型。不能声明不完整类型的对象,但可以声明指向它们的指针

宣言

typedef struct
{
    char value;
    struct Element *next;
} Element;
是合法的,但它不会使
next
成为指向封闭类型的指针。它使它成为指向某个不完整类型的指针,在声明完整类型之前,您将无法引用它

你的第二个声明是太多没有意义但仍然合法的事情之一

您可以考虑省略TyWIFF,并始终引用类型为<代码>结构元素< /代码>。很多人都喜欢为一个结构类型使用一个单词的名称,但我个人的观点是这样做没有多大好处(除非该类型是真正不透明的,即该类型的用户甚至不知道它是一个结构)。这是风格的问题

注意,您需要在定义本身中将类型称为
struct Element
,而不是
Element
,因为typedef name
Element
还不可见

struct标记和typedef具有相同的名称这一事实似乎令人困惑,但这是完全合法的。Stutt标签和Type Debug在单独的命名空间中(在C意义上,而不是C++感);结构标记只能紧跟在
struct
关键字之后出现

另一种方法是将typedef与结构定义分开:

typedef struct Element Element;

struct Element {
    char value;
    Element *next;
};

(您可以在
typedef
中使用不完整的类型名称)

您的第一个变体是正确的。您的第二个变体并不像它看起来那样做

<>在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
第一个变体的一个替代方案是,在任何地方(包括在类型定义内)都可以使用“Element”而不是“struct Element”

typedef struct Element Element;
struct Element
{
    char value;
    Element *next;
};

但在C中,无法避免必须手动确保“struct-Element”与“Element”相同。如果你不想处理它,C++正在那边等你,p> 要存储指向结构的指针,编译器不需要知道它的内容或大小,只需要知道指针的大小

在第一个示例中,
struct元素
在结构定义之前是一个不完整的类型,但这是有效的,因为您只声明了指向它的指针,而不是结构本身的实例


在第二个示例中,您根本没有声明
struct元素
结构(
struct元素
Element
不是一回事)。尽管仍然可以在结构中包含指针,但它并不是指同一类型,而是指尚未定义的
struct元素。typedef中的结构定义是一个匿名结构,因此只能使用
元素
(不带struct关键字)引用它。因此,第二个示例无法按预期工作。

在第二个示例中,您的*next实际上变成了一个struct struct{},您需要了解定义的实际类型。@bigkm替换
struct Element*next带有
元素*下一步报告为错误。或者你是什么意思?@bigkm:struct-struct{}
是什么意思?在第二种情况下,
next
是指向
struct元素的指针;问题是
struct Element
是一个不完整的类型。如何版本:啊,哇,这很有意义,我不知道指向不完整类型的指针。谢谢,谢谢。你总会学到一些新的东西,用那种语言“哇”的你。(你的回答晚了几秒钟,所以我接受第一个,但这一个定义有助于理解更多)哦,尤其是你之前使用typedef的第三个版本;-)提醒一下:您不能在自己的代码中安全地使用像“\u Anonymous\u 1”这样的名称,因为以下划线开头的标识符是为实现保留的。我知道您在伪代码中使用了它,旨在显示编译器中发生了什么,所以这不是一个更正,只是一个澄清。是的,这是经过深思熟虑的。(我曾考虑在那里投一个美元符号,但我认为这会让人迷惑,而不是有帮助。)
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;
};