用struct理解typedef

时间:2016-02-04 11:33:50

标签: c struct typedef

我很难理解这段代码:

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

typedef node * nodepointer;

所以,我们正在使用typedef构建struct节点...我假设我们这样做是为了初始化struct而不需要“struct”关键字。

我想问为什么在结构定义中我们使用名称“node”两次(在开始和结束时)。

其次typedef node * nodepointer;指向的是什么。在这种情况下是否有必要使用typedef?这个表达式node * nodepointer;不相等吗?

6 个答案:

答案 0 :(得分:4)

首先,让我们在这里说清楚:typedef不是变量的声明。它只是将新类型 name 别名为现有类型说明符。

typedef <type specifier> new_type_name;

所以,这里发生的事情当然可以欺骗未经训练的人。

struct node本身是名为struct的{​​{1}},其中包含两个属性node和一个int data

我稍后会更多地进入struct node *next,但现在这很简单。

然后,周围的next接受该结构并为其命名typedef。为什么这样,你可能会问?

这是因为在C(与C ++不同)中,tag name使用结构需要在类型前加上node

struct

使用typedef,我们使用名为struct Foo { // ... }; Foo bar; // ERROR struct Foo bar; // OK typename 为结构命名。这个例子应该让它更清晰。

node

请记住,您可以定义没有标签的结构,因此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 incomplete type。不完整的类型,简单地说,是声明的类型(给定名称和类型,即struct node *next),但不是定义(给定&# 39;身体&#39;,即struct node;)。

不完整的类型定义之前无法使用,除非您指向

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) }; [指向] [?]

无。它只是别名(标签或昵称&#39;)到另一种类型。它只是说类型typedef node * nodepointer;实际上是nodepointer

这也意味着任何需要node *的内容都可以使用node *,反之亦然。

  

在这种情况下是否有必要使用nodepointer

没必要,没有。您也可以在任何地方使用typedef而不是node *。大多数编码标准对nodepointer类型的指针类型(如您的示例)不屑一顾,因为它会增加代码库的混淆(正如您在此问题中所证明的那样!:))

  

表达式typedef不相等吗?

不。同样,请记住node * nodepointer;只是指定引用相同类型的另一种方式。它实际上并没有创建任何内存,而是为现有类型提供一个新名称。

答案 1 :(得分:3)

这个结构是自引用的,这意味着它包含一个指向自身的指针。

如果您不使用标记node,您将如何在以后指定指针类型。因此,首先需要node

struct node {
    struct node *ptr;    
};
// you can do this way too
typdef struct node node;

完成node需要最后typedef

typedef node * nodepointer;,现在您可以使用nodepointer表示node*。无论node*出现在何处,您只需替换为nodepointer

即可
  

在这种情况下是否有必要使用typedef?

由你决定,

  

这个表达式是node * nodepointer;不相等?

不,这只声明nodepointer指针变量,而typedef通过名称创建别名node * nodepointer

答案 2 :(得分:1)

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节
  

如果在a中的任何一点可以看到多个特定标识符的声明   在翻译单元中,句法上下文消除了引用不同实体的用法。   因此,各种标识符类别都有单独的名称空间,如下所示:

     

- 标签名称(通过标签声明和使用的语法消除歧义);

     

- 结构,联合和枚举的标记(通过跟随any32消除歧义)   关键字struct,union或enum);

     

- 结构或工会的成员;每个结构或联合都有一个单独的名称   其成员的空间(通过用于访问的表达式的类型消除歧义   会员通过。或 - &gt;操作者);

     

- 所有其他标识符,称为普通标识符(在普通声明符中声明或作为   枚举常量)。

答案 3 :(得分:1)

问题是你一次做两件事:声明结构类型并将该结构定义为名称。

对于typedef,语法为

typedef <some type> name;

其中某些类型可能是简单类型,例如intlong等,也可能是struct foo之类的复杂类型,而且无论是struct foo还是typedef struct foo { int bar; } foo; 都是如此之前宣布或在此时宣布。

所以

typedef <some type> name;

对应

<some type>

其中struct foo { int bar; }namefoo<some type>

至于第二个问题,

在这种情况下,node *namenodepointertypedef node * nodepointer; ,所以

nodepointer

键入node作为指向struct node { ... }的指针(您之前已将typedefd设为public class MainClass{ public static void main(String[] args) { String out=""; String Format="0000.0000"; DecimalFormat dfm=new DecimalFormat(Format); out=dfm.format(123.45); System.out.println("out="+out); } }

答案 4 :(得分:0)

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;

这些都是等效的。

两个类型名nodestruct node的共存是可能的,因为它们被称为“struct tags”(如“struct node”中的“node”)与其他名称分开,因此可以用来命名别的东西,另外,没有碰撞。要键入一个结构,以便新类型具有struct标签的名称是一个常见的例子,但名称“node”可以用于其他任何东西(int变量,无论如何)。

答案 5 :(得分:0)

对于struct,您要定义结构名称(在大括号之前),然后是类型名称(在大括号之后):

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

下一个创建另一个类型,指向节点的指针:

 typedef node* nodepointer;

现在都可以用来创建变量:

 node myNode;
 nodepointer aPtr;