用struct 理解typedef
我很难理解这段代码:
typedef struct node { int data; struct node * next; } node; typedef node * nodepointer;
所以,我们正在使用typedef构建struct节点…我假设我们这样做是为了初始化struct而不需要“struct”关键字。
我想问一下为什么在struct定义中我们使用名称“node” 两次 (在开始和结束时)。
其次是typedef node * nodepointer;
指着。 在这种情况下是否有必要使用typedef? 这个表达式是node * nodepointer;
不平等?
问题是你一次做两件事:声明结构类型并将结构类型定义为名称。
对于typedef
,语法是
typedef name;
其中某些类型可能是一个简单的类型,如int
, long
等,或者像struct foo
这样的复杂类型,而且无论之前是什么类型的struct foo
都已经声明过,或者它是在那个时候声明的。
所以
typedef struct foo { int bar; } foo;
对应于
typedef name;
其中
是struct foo { int bar; }
和name
是foo
至于第二个问题,
在这种情况下,
是node *
, name
是nodepointer
,所以
typedef node * nodepointer;
将typepofing一个nodepointer
作为指向node
的指针(你之前已经将typedefd作为struct node { ... }
)
首先,让我们在这里说清楚: typedef
不是变量的声明。 它只是将新类型名称别名为现有类型说明符。
typedef new_type_name;
所以这里发生的事情肯定会欺骗未经训练的眼睛。
struct node
本身是一个名为node
的struct
,它有两个属性int data
和一个struct node *next
。
我马上就会进入next
,但现在这很简单。
然后,周围的typedef
接受该结构并为其指定名称node
。 为什么这样,你可能会问?
这是因为在C(与C ++不同)中,使用其标记名称的结构需要在类型前加上struct
。
struct Foo { // ... }; Foo bar; // ERROR struct Foo bar; // OK
使用typedef,我们使用名为node
的typename为结构命名。 这个例子应该让它更清楚一些。
typedef struct Foo { // ... } FooType; Foo bar; // ERROR struct Foo bar; // OK FooType bar; // OK struct FooType bar; // ERROR
请记住,您可以定义没有标签的结构,从而typedef
它们。
typedef struct { // ... } FooType; FooType bar; // OK
虽然我会解释为什么你不能在你的例子中这样做。
示例中的属性struct node *next
是不完整的类型 。 不完整的类型,简单地说,是已声明的类型(给定名称和类型,即struct node;
),但未定义 (给定’body’,即struct node { int foo; };
)。
除非您指向它们 , 否则在定义不完整类型之前不能使用它们 。
struct Foo; struct Foo bar; // ERROR: Foo is not defined. struct Foo *bar; // OK - it's just a pointer. We know the size of a pointer. struct Foo { // ... }; struct Foo bar; // OK - it's defined now.
因此,通过类型struct node *next
声明,我们已经有了struct node
的声明但没有定义 ,这使得一个指向struct node
的指针成为可能。
您还可以推断,直接使用struct node
不起作用:
struct node { struct node next; // ERROR - `struct node` becomes infinitely big struct node *next; // OK - a pointer is usually 4/8 bytes (we at least know its size at this point) };
回答你的最后三个问题:
什么[
typedef node * nodepointer;
]typedef node * nodepointer;
[指向[?]
没有。 它只是另一种类型的别名 (标签或“昵称”)。 它只是说类型nodepointer
是一个node *
。
这也意味着任何需要node *
东西都可以使用nodepointer
,反之亦然。
在这种情况下是否有必要使用
typedef
?
没必要,没有。 你也可以在任何地方使用node *
而不是nodepointer
。 大多数编码标准对类型定义类型指针类型(如您的示例)不满意,因为它会增加代码库的混淆(正如您在此问题中所certificate的那样!:))
是[]表达式
node * nodepointer;
不平等?
不。 同样,请记住typedef
只是指定引用相同类型的另一种方式。 它实际上并不创建任何内存,而是为现有类型提供新名称。
这个结构是自引用的,这意味着它包含一个指向自身的指针。
如果不使用标记node
,稍后如何指定指针类型。 因此需要第一个node
struct node { struct node *ptr; }; // you can do this way too typdef struct node node;
完成typedef
需要最后一个node
。
通过typedef node * nodepointer;
,现在你可以使用nodepointer
来表示node*
。 无论在哪里发生node*
,您都可以简单地用nodepointer
替换
在这种情况下是否有必要使用typedef?
它是由你决定,
这个表达式是node * nodepointer; 不平等?
不,这只声明nodepointer
是指针变量,而typedef
通过名称nodepointer
创建type , node *
的nodepointer
。
typedef struct node int data; struct node * next; } node;
第一行中的node
是结构的标记 。
最后一行中的node
是类型的名称。
这两者不必相同。
如果您希望它们不同,代码将如下所示。
typedef struct helloNode int data; struct helloNode * next; } node;
类型的名称是node
。 结构的名称是helloNode
有关更多技术说明,这两个nodes
位于不同的名称空间中 。 并且可以有不同的价值观。
来自http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf的第6.3节
如果在翻译单元中的任何点处可见多于一个特定标识符的声明,则句法上下文消除了引用不同实体的用法的歧义。 因此,各种标识符类别都有单独的名称空间,如下所示:
– 标签名称(通过标签声明和使用的语法消除歧义);
– 关键字struct,union或enum)的结构,联合和枚举的标记(通过遵循any32消除歧义);
– 结构或工会的成员; 每个结构或联合为其成员都有一个单独的名称空间(通过。或 – >运算符用于访问成员的表达式的类型消除歧义);
– 所有其他标识符,称为普通标识符(在普通声明符中声明或作为枚举常量)。
对于struct,您要定义结构名称(在大括号之前),然后是类型名称(在大括号之后):
typedef struct node { int data; struct node* next; } node;
下一个创建另一个类型,指向节点的指针:
typedef node* nodepointer;
现在两者都可用于创建变量:
node myNode; nodepointer aPtr;
Daleisha正确地说你需要struct标签才能声明next
指向这些结构的指针。 在引入之前,您无法写下该类型名称。 另一种可能性是向前声明结构:
struct node; typedef struct node node; struct node { node *next; int i; };
但是,这引入了一个或多个node
更多提及。
作为一个副作用,引入struct标签“node”使得仍然可以编写正常的struct node
,而typedef本身是不可能的。
第二个typedef仍然是typedef,它不引入变量而是引入类型名称。 在您的源代码段中的所有声明之后,您可以说
struct node *np1; node *np1; nodepointer np1;
这些都是等价的。
两个类型名称node
和struct node
的共存是可能的,因为“结构标记”(如“结构节点”中的“节点”),因为它们被调用,与其他名称分开保存,因此可用于另外,没有碰撞就命名别的东西。 要键入一个结构,以便新类型具有结构标记的名称是一个常见的例子,但名称“node”可以用于其他任何东西(int变量,无论如何)。