C 与 C++ 中的 Typedef 结构
Typedef struct in C Vs C++
这会在 C++ 中产生错误,但在 C 中不会:
typedef struct nodes
{
int data;
struct node *next;
}node;
它在 C++ 中给出以下错误。
/home/DS cpp/linkedlist.cpp|10|error: conflicting declaration ‘typedef struct nodes node’|
/home/DS cpp/linkedlist.cpp|9|error: ‘struct node’ has a previous declaration as ‘struct node’|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
为了在 C++ 中工作,我必须将其更改为:
typedef struct node
{
int data;
struct node *next;
}node;
我不明白为什么会这样,我想知道C和C++的执行顺序,以便我理解。
让我们稍微分析一下您的代码:
typedef struct nodes
{
int data;
struct node *next;
}node;
这声明并定义了 struct nodes
,一个具有两个成员的类型,并声明了一个类型别名,因此我们只能将其称为 node
。
现在,在 C++ 中,成员声明 struct node *next
automatically forward-declares a type called node
。这会与您的 typedef
目标 node
发生冲突:就好像您试图为两种类型赋予相同的名称。
在C里是没有冲突的,因为叫node
的类型其实只能指struct node
.
第二个代码片段之所以有效,是因为在解析成员声明期间 struct node
已经存在,因此没有新的类型被前向声明……并且因为您随后所做的只是在同一个 typedef
语句,C++并不关心,知道都是同一种类型(struct T
是 T
;区别在于语法,而不是名义上)。
[C++11: 7.1.3/3]:
In a given non-class scope, a typedef
specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [ Example:
typedef struct s { / ... / } s;
typedef int I;
typedef int I;
typedef I I;
—end example ]
[C++11: 7.1.3/6]:
In a given scope, a typedef
specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type. [ Example:
class complex { / ... / };
typedef int complex; // error: redefinition
—end example ]
当然,在 C++ 中,这一切都没有实际意义,您应该只写:
struct node
{
int data;
node* next;
};
您不需要 typedef
-away 详细类型说明符 struct
.
你给出的C例子应该是错误的。您正在使用未使用 struct node
.
定义的标签名称 (node
)
鉴于这两个选择,第二个是要使用的。我更喜欢经济一点:
typedef struct node_t
{
int data;
struct node_t *next;
} node_t;
在C或C++中,标签名称有自己的命名空间,所以标签和typedef名称使用相同的名称是没有问题的。在 C 中,这允许您使用 node_t
或 struct node_t
来引用此结构类型。如果声明的类型名称不存在,C++ 将在标记名称中搜索类型名称,因此不需要上述双重定义,但不会造成伤害。
在这两种语言中,在完全定义类型之前的任何时候都需要显式 struct node_t
版本,因此任何自引用和任何前向引用都将使用 struct
版本。我更喜欢头文件中的这个,主要是因为它减少了 #include
指令顺序的问题。
PS:这 确实 在任何一种语言中都有效(请参阅 LRIO 对 C++11 标准的指针的回答)并且已被足够多的双语甚至双语使用纯 C++ 头文件,它不太可能很快消失)所以这是一种非常简单的方法,只适用于任何一种语言。
这会在 C++ 中产生错误,但在 C 中不会:
typedef struct nodes
{
int data;
struct node *next;
}node;
它在 C++ 中给出以下错误。
/home/DS cpp/linkedlist.cpp|10|error: conflicting declaration ‘typedef struct nodes node’|
/home/DS cpp/linkedlist.cpp|9|error: ‘struct node’ has a previous declaration as ‘struct node’|
||=== Build failed: 2 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|
为了在 C++ 中工作,我必须将其更改为:
typedef struct node
{
int data;
struct node *next;
}node;
我不明白为什么会这样,我想知道C和C++的执行顺序,以便我理解。
让我们稍微分析一下您的代码:
typedef struct nodes
{
int data;
struct node *next;
}node;
这声明并定义了 struct nodes
,一个具有两个成员的类型,并声明了一个类型别名,因此我们只能将其称为 node
。
现在,在 C++ 中,成员声明 struct node *next
automatically forward-declares a type called node
。这会与您的 typedef
目标 node
发生冲突:就好像您试图为两种类型赋予相同的名称。
在C里是没有冲突的,因为叫node
的类型其实只能指struct node
.
第二个代码片段之所以有效,是因为在解析成员声明期间 struct node
已经存在,因此没有新的类型被前向声明……并且因为您随后所做的只是在同一个 typedef
语句,C++并不关心,知道都是同一种类型(struct T
是 T
;区别在于语法,而不是名义上)。
[C++11: 7.1.3/3]:
In a given non-class scope, atypedef
specifier can be used to redefine the name of any type declared in that scope to refer to the type to which it already refers. [ Example:typedef struct s { / ... / } s; typedef int I; typedef int I; typedef I I;
—end example ]
[C++11: 7.1.3/6]:
In a given scope, atypedef
specifier shall not be used to redefine the name of any type declared in that scope to refer to a different type. [ Example:class complex { / ... / }; typedef int complex; // error: redefinition
—end example ]
当然,在 C++ 中,这一切都没有实际意义,您应该只写:
struct node
{
int data;
node* next;
};
您不需要 typedef
-away 详细类型说明符 struct
.
你给出的C例子应该是错误的。您正在使用未使用 struct node
.
node
)
鉴于这两个选择,第二个是要使用的。我更喜欢经济一点:
typedef struct node_t
{
int data;
struct node_t *next;
} node_t;
在C或C++中,标签名称有自己的命名空间,所以标签和typedef名称使用相同的名称是没有问题的。在 C 中,这允许您使用 node_t
或 struct node_t
来引用此结构类型。如果声明的类型名称不存在,C++ 将在标记名称中搜索类型名称,因此不需要上述双重定义,但不会造成伤害。
在这两种语言中,在完全定义类型之前的任何时候都需要显式 struct node_t
版本,因此任何自引用和任何前向引用都将使用 struct
版本。我更喜欢头文件中的这个,主要是因为它减少了 #include
指令顺序的问题。
PS:这 确实 在任何一种语言中都有效(请参阅 LRIO 对 C++11 标准的指针的回答)并且已被足够多的双语甚至双语使用纯 C++ 头文件,它不太可能很快消失)所以这是一种非常简单的方法,只适用于任何一种语言。