我是C编程的初学者,但我想知道在定义结构时使用typedef与不使用typedef之间有什么区别。在我看来,这两者并没有什么区别,它们实现的目标是一样的。

struct myStruct{
    int one;
    int two;
};

vs.

typedef struct{
    int one;
    int two;
}myStruct;

当前回答

我看需要澄清一下。C和c++没有不同的类型定义。c++最初不过是C之上的一组附加的包含。

如今几乎所有C/ c++开发人员都面临的问题是:a)大学不再教授基础知识,b)人们不理解定义和声明之间的区别。

这样的声明和定义存在的唯一原因是链接器可以计算到结构中字段的地址偏移量。这就是为什么大多数人使用实际上写得不正确的代码——因为编译器能够确定寻址。当有人试图提前做一些事情,比如队列、链表或承载O/S结构时,问题就出现了。

声明以'struct'开始,定义以'typedef'开始。

此外,结构体具有前向声明标签和已定义标签。大多数人不知道这一点,而是将forward声明标签用作定义标签。

错误的:

struct myStruct
   {
   int field_1;
   ...
   };

它们只是使用forward声明来标记结构——所以现在编译器知道它了——但它不是实际定义的类型。编译器可以计算寻址——但这不是它打算使用的方式,原因我马上会说明。

使用这种形式的声明的人,必须在几乎所有的引用中都加上“struct”——因为它不是一个正式的新类型。

相反,任何不引用自身的结构都应该这样声明和定义:

typedef struct
   {
   field_1;
   ...
   }myStruct;

现在它是一个实际的类型,当使用时,你可以使用at作为'myStruct',而不必在它前面加上'struct'这个词。

如果你想要一个指向该结构的指针变量,那么包括一个二级标签:

typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;

现在你有了一个指向该结构的指针变量,自定义的。

前置声明——

现在,这里有一些有趣的东西,forward声明是如何工作的。如果希望创建引用自身的类型,如链表或队列元素,则必须使用前向声明。编译器不会考虑定义的结构,直到它到达最后的分号,所以它只是在这一点之前声明。

typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;

现在,编译器知道,尽管它还不知道整个类型是什么,但它仍然可以使用前向引用引用它。

请正确地声明和定义结构类型。这其实是有原因的。

其他回答

在C语言中,结构、联合和枚举的类型说明关键字是强制性的,也就是说,当引用类型时,你总是必须在类型名(它的标记)前面加上struct、联合或enum。

您可以通过使用typedef来摆脱关键字,这是一种信息隐藏的形式,因为在声明对象时,对象的实际类型将不再可见。

因此建议(参见Linux内核编码风格指南,第5章)只在以下情况下这样做 实际上,您希望隐藏这些信息,而不仅仅是为了节省一些按键。

你应该使用typedef的一个例子是不透明类型,它只与相应的访问器函数/宏一起使用。

与其他构造一样,typedef用于为数据类型赋予新名称。在这种情况下,这样做主要是为了使代码更干净:

struct myStruct blah;

vs.

myStruct blah;

Struct和typedef是两个完全不同的东西。

struct关键字用于定义或引用结构类型。例如,这个:

struct foo {
    int n;
};

创建名为struct foo的新类型。foo是一个标签;只有当它前面紧跟struct关键字时,它才有意义,因为标记和其他标识符位于不同的名称空间中。(这类似于c++的名称空间概念,但限制更大。)

类型定义(typedef),尽管有这个名字,但并不定义一个新的类型;它只是为现有类型创建一个新名称。例如,给定:

typedef int my_int;

My_int是int的新名称;My_int和int是完全相同的类型。类似地,给定上面的结构体定义,你可以这样写:

typedef struct foo foo;

该类型已经有一个名称,struct foo。typedef声明为同一类型赋予了一个新名称foo。

语法允许你将struct和typedef组合成一个声明:

typedef struct bar {
    int n;
} bar;

这是一个常用的习语。现在你可以把这个结构类型称为struct bar或者bar。

注意,typedef名称直到声明结束才可见。如果结构体包含指向自身的指针,则必须使用结构体版本来引用它:

typedef struct node {
    int data;
    struct node *next; /* can't use just "node *next" here */
} node;

有些程序员会为struct标记和typedef名称使用不同的标识符。在我看来,这并没有什么好理由;使用相同的名字是完全合法的,而且更清楚地表明他们是同一类型的人。如果你必须使用不同的标识符,至少使用一致的约定:

typedef struct node_s {
    /* ... */
} node;

(Personally, I prefer to omit the typedef and refer to the type as struct bar. The typedef saves a little typing, but it hides the fact that it's a structure type. If you want the type to be opaque, this can be a good thing. If client code is going to be referring to the member n by name, then it's not opaque; it's visibly a structure, and in my opinion it makes sense to refer to it as a structure. But plenty of smart programmers disagree with me on this point. Be prepared to read and understand code written either way.)

(c++有不同的规则。给定结构体blah的声明,即使没有类型定义,也可以直接将类型引用为blah。使用typedef可能会让你的C代码更像c++——如果你认为这是件好事的话。)

不能对typedef结构使用前向声明。

该结构本身是匿名类型,因此没有实际的名称来转发声明。

typedef struct{
    int one;
    int two;
} myStruct;

像这样的前向声明是行不通的:

struct myStruct; //forward declaration fails

void blah(myStruct* pStruct);

//error C2371: 'myStruct' : redefinition; different basic types

我看需要澄清一下。C和c++没有不同的类型定义。c++最初不过是C之上的一组附加的包含。

如今几乎所有C/ c++开发人员都面临的问题是:a)大学不再教授基础知识,b)人们不理解定义和声明之间的区别。

这样的声明和定义存在的唯一原因是链接器可以计算到结构中字段的地址偏移量。这就是为什么大多数人使用实际上写得不正确的代码——因为编译器能够确定寻址。当有人试图提前做一些事情,比如队列、链表或承载O/S结构时,问题就出现了。

声明以'struct'开始,定义以'typedef'开始。

此外,结构体具有前向声明标签和已定义标签。大多数人不知道这一点,而是将forward声明标签用作定义标签。

错误的:

struct myStruct
   {
   int field_1;
   ...
   };

它们只是使用forward声明来标记结构——所以现在编译器知道它了——但它不是实际定义的类型。编译器可以计算寻址——但这不是它打算使用的方式,原因我马上会说明。

使用这种形式的声明的人,必须在几乎所有的引用中都加上“struct”——因为它不是一个正式的新类型。

相反,任何不引用自身的结构都应该这样声明和定义:

typedef struct
   {
   field_1;
   ...
   }myStruct;

现在它是一个实际的类型,当使用时,你可以使用at作为'myStruct',而不必在它前面加上'struct'这个词。

如果你想要一个指向该结构的指针变量,那么包括一个二级标签:

typedef struct
   {
   field_1;
   ...
   }myStruct,*myStructP;

现在你有了一个指向该结构的指针变量,自定义的。

前置声明——

现在,这里有一些有趣的东西,forward声明是如何工作的。如果希望创建引用自身的类型,如链表或队列元素,则必须使用前向声明。编译器不会考虑定义的结构,直到它到达最后的分号,所以它只是在这一点之前声明。

typedef struct myStructElement
   {
   myStructElement*  nextSE;
   field_1;
   ...
   }myStruct;

现在,编译器知道,尽管它还不知道整个类型是什么,但它仍然可以使用前向引用引用它。

请正确地声明和定义结构类型。这其实是有原因的。