两种声明结构体的方式有什么区别?

4
作为一个初学者,我正在学习关于链表和其他数据结构的C++知识。在查看了一些在线实现后,我发现了这两种定义struct的方式。它们之间有什么区别呢?其中一种在下一个指针前添加了“struct”,而另一种则没有。

方式1:


struct Node { int data; Node* next; };

Way 2:

struct Node { int data; struct Node* next; };
struct node
{
   int data;
   node *next;
};

方式二:

struct node
{
   int data;
   struct node *next;
};

我可能对此有所错误,但这只是遗留问题,没有任何区别。 - Raxvan
5
第二个是C语言的方式。 - sim
6个回答

9
struct node *next;

只有在C代码中才是必需的。在C中,可以这样做:

node *next;

不允许使用。然而,在C++中,您可以同时使用这两种方法。在这种情况下,它们之间没有区别。
在C++中,只有在声明中存在某种歧义或尚未定义结构体时,才需要使用struct关键字。(例如,第一个是stat函数,在POSIX系统上是函数和结构体)。

关于最后一段,你忘记了我经验中最常见的情况,即在参数或字段声明中直接提供不完整的定义。例如 void foo(struct Bar *bar);,其中 Bar 实际上没有在提供此声明的头文件中定义。编辑:我现在看到这已经是两年前的事情了,我的用例已经在下一个答案中提供了。嗯,算了。 - Matteo Italia
好的,我显然还没有完全清醒 :-) 我把 "Feb 16" 错认为 "Feb 2016" 了。 - Matteo Italia

8
两者之间有什么区别。
区别在于后者(称为“详细类型说明符”)声明了node是一个结构体。
在这种情况下,声明node是一个结构体是多余的,因为已经声明过了。
struct node
^^^^^^^^^^^ <-- node is a struct
{
   int data;
   node *next;
};

一个存在差异的案例示例:

struct a {
    //b* pointer;      // oops, we don't know what b is
    struct b* pointer; // OK, b is a struct
};

struct b{};

通常情况下,不一定要使用详细的类型说明符,因为可以使用单独的声明代替:

struct b;

struct a {
    b* pointer;
};

struct b{};

选择它们之间取决于个人偏好。
我说“通常”是因为有时你需要它来消除同名变量和类型的歧义:
int foo;
struct foo{};

int main()
{
    foo = 10;            // refers to int
    struct foo instance; // refers to the struct
}

一般来说,使用同一个名称来表示多个不同的事物是一种糟糕的设计,因此这并不是很典型。


最后,有时候希望编写可以同时在C和C++中包含的头文件。这种头文件必须使用两种语言的共同子集。

在C中,node不是类型名称,而是结构体的标签。在C中需要使用struct关键字来引用结构体标签。


3
第二个版本在C语言中是必需的,但在C++中不好的风格,在C++中几乎没有情况需要像这样添加关键字。
请注意,除非出于学术目的,否则无需在C++中编写自己的链表实现。使用std::list或std::forward_list。

“almost”?您有需要使用该关键字的示例吗?没关系,Arnav Borborah在他的编辑中提到了一个。除非您还有其他的? - Nelfeal

1

在您的情况下,没有任何区别。然而,请考虑以下示例:

struct foo { struct node* f; };   // <- this is fine
struct foo_broken { node* f; };   // <- wont compile

struct node { };

int main() {
    foo f;
    //foo_broken g;
}

使用关键字struct可以在声明node之前声明成员。如果没有使用struct,编译器会报错(对于foo_broken):

error: ‘node’ does not name a type

也就是说,放置关键字struct就像是一个前向声明。要使用foo,你需要提供一个node的声明,但它可以放在foo的声明之后。

1
这是因为C++是从C语言发展而来的,继承了C语言的语法,即使不再需要使用struct显式声明变量的类型,该语言仍保留了这两种语法。在某些情况下,例如解决具有相同名称的不同类型/函数等之间的歧义,这将产生差异。此外,通过在C++中保持此语法有效,可以帮助人们将C代码移植到C++而不引入错误。
在C语言中,默认情况下必须始终在结构体名称前面放置struct关键字。因此,只有Way#2是有效的C语言:
struct node
{
    int data;
    node *next; //error in C!
};

struct node
{
    int data;
    struct node *next; //compiles
};

但是在C代码中,你经常会看到struct声明与typedef配对使用,以创建新的类型,例如:

typedef struct node_t
{
    int data;
    struct node *next;
} node;

这将允许在不加struct的情况下使用node作为一种类型。在C++中,它有效地自动化了所有代码中的structclass类型的typedef,这就是为什么可以在相应限定符之前不加structclass名称来使用它们的原因。

0

C++ 中这两种声明没有区别


1
其他答案和评论解释了在某些罕见情况下可能会有差异。 - Christian Hackl

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接