typedef结构与结构定义

我是C编程的初学者,但我想知道在定义结构时使用typedef与不使用typedef有何区别。 在我看来,实际上没有什么区别,他们也完成了同样的事情。

struct myStruct{ int one; int two; }; 

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

常见的习惯用法是:

 typedef struct X { int x; } X; 

它们是不同的定义。 为了使讨论更清楚,我将分开这个句子:

 struct S { int x; }; typedef struct SS; 

在第一行中,您要在结构体名称空间中定义标识符S (而不是C ++意义上的)。 您可以使用它并通过将参数的types定义为struct S来定义新定义types的variables或函数参数:

 void f( struct S argument ); // struct is required here 

第二行在全局名称空间中添加一个types别名S ,从而允许您只写:

 void f( S argument ); // struct keyword no longer needed 

请注意,由于两个标识符名称空间不同,因此在结构体和全局空间中定义S不是错误,因为它不是重新定义相同的标识符,而是在不同的地方创build不同的标识符。

为了使区别更清楚:

 typedef struct S { int x; } T; void S() { } // correct //void T() {} // error: symbol T already defined as an alias to 'struct S' 

您可以定义一个与struct相同名称的函数,因为这些标识符保存在不同的空格中,但是不能像这些标识符相同的名称那样定义一个与typedef同名的函数。

在C ++中,它与定位符号的规则有细微的不同。 C ++仍然保留两个不同的标识符空间,但与C中不同的是,当您只在类标识符空间中定义符号时,不需要提供struct / class关键字:

  // C++ struct S { int x; }; // S defined as a class void f( S a ); // correct: struct is optional 

search规则有哪些变化,而不是定义标识符的位置。 编译器将search全局标识符表,并且在S未find之后,它将在类标识符内searchS

前面介绍的代码的行为方式相同:

 typedef struct S { int x; } T; void S() {} // correct [*] //void T() {} // error: symbol T already defined as an alias to 'struct S' 

在第二行S函数的定义之后,struct S不能被编译器自动parsing,并且要创build一个对象或者定义一个该types的参数,你必须回退到包含struct关键字:

 // previous code here... int main() { S(); struct S s; } 

另外一个不同的地方是给结构一个名字(比如struct myStruct)也可以提供结构的前向声明。 所以在其他文件中,你可以写:

 struct myStruct; void doit(struct myStruct *ptr); 

而不必访问定义。 我build议你结合你的两个例子:

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

这给你更简洁的typedef名称的方便,但仍然允许你使用完整的结构名称,如果你需要。

structtypedef是两个完全不同的东西。

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

 struct foo { int n; }; 

创build一个名为struct foo的新types。 名字foo是一个标签 ; 只有当它紧挨着struct关键字时才有意义,因为标签和其他标识符在不同的名称空间中 。 (这与namespace的C ++概念类似,但是比它更受限制。)

一个typedef ,尽pipe名字,没有定义一个新的types; 它只是为现有types创build一个新名称。 例如,给出:

 typedef int my_int; 

my_intint的新名称; my_intint完全相同的types。 同样,给定上面的struct定义,你可以写:

 typedef struct foo foo; 

该types已经有一个名称, struct footypedef声明给出了一个新的名字foo

该语法允许您将一个structtypedef到一个声明中:

 typedef struct bar { int n; } bar; 

这是一个常见的成语。 现在你可以把这个结构体的types作为struct bar或者像bar一样引用。

请注意,typedef名称在声明结束之前不可见。 如果结构包含一个指向它自己的指针,则可以使用struct版本来引用它:

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

有些程序员会为结构标签和typedef名称使用不同的标识符。 在我看来,这没有什么好的理由。 使用相同的名字是完全合法的,并且使得它们更清楚,它们是相同的types。 如果你必须使用不同的标识符,至less要使用一致的约定:

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

(就个人而言,我更喜欢省略typedef并将这个types称为struct bartypedef保存了一些input,但是隐藏了它是一个结构types的事实,如果你想让这个types是不透明的,如果客户端代码是按名称引用成员n ,那么它不是不透明的;它显然是一个结构,在我看来,把它作为一个结构是合理的,但是很多聪明的程序员不同意我在这一点上,准备阅读和理解任何一种写法。)

(C ++有不同的规则,给定一个struct blah的声明,你可以引用types为blah ,即使没有typedef。使用typedef可能会让你的C代码更像C ++ – 如果你认为这是一个好的事情。)

在C(而不是C ++)中,你必须声明结构variables,如:

 struct myStruct myVariable; 

为了能够使用myStruct myVariable; 相反,您可以typedef结构:

 typedef struct myStruct someStruct; someStruct myVariable; 

您可以将struct definition和typedef s合并到一个声明匿名structtypedef的声明中。

 typedef struct { ... } myStruct; 

在C中,结构,联合和枚举的types说明符关键字是强制性的,也就是说,当引用types时,您总是必须在types的名称(它的标记 )前加上structunionenum

您可以使用typedef来删除关键字,这是一种隐藏信息的forms,因为在声明对象时,实际types将不再可见。

因此,build议(例如参见Linux内核编码风格指南 ,第5章)只在实际上想要隐藏这些信息时这样做,而不仅仅是为了节省一些击键。

你应该使用typedef一个例子是一个不透明的types,它只能用于相应的存取函数/macros。

如果你使用没有typedef struct ,你将永远不得不写

 struct mystruct myvar; 

写作是非法的

 mystruct myvar; 

如果使用typedef ,则不再需要struct前缀。

当你使用这个struct时候,会有不同。

你必须做的第一个方法是:

 struct myStruct aName; 

第二种方法允许您删除关键字struct

 myStruct aName; 

typedef和其他的结构一样,用来给数据types一个新的名字。 在这种情况下,主要是为了使代码更清洁:

 struct myStruct blah; 

 myStruct blah; 

您不能使用typedef struct前向声明。

struct本身是一个匿名types,所以你没有一个实际的名字来转发declare。

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

像这样的前向声明将不起作用:

 struct myStruct; //forward declaration fails void blah(myStruct* pStruct); //error C2371: 'myStruct' : redefinition; different basic types 

下面的代码创build一个具有别名myStruct的匿名结构:

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

你不能没有别名来引用它,因为你没有指定结构的标识符。

我看到一些澄清是为了这个。 C和C ++不会以不同的方式定义types。 C ++本来只不过是在C之上的一个附加集合。

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

这种声明和定义存在的唯一原因是,链接器可以计算结构中字段的地址偏移量。 这就是为什么大多数人摆脱了实际写入不正确的代码 – 因为编译器能够确定寻址。 当有人试图进行某些事情时,问题就出现了,比如队列,链表,或者支持O / S结构。

声明以“struct”开始,定义以“typedef”开头。

此外,结构体具有前向声明标签和定义的标签。 大多数人不知道这一点,并使用正向声明标签作为定义标签。

错误:

 struct myStruct { int field_1; ... }; 

他们只是使用forward声明来标注结构,所以现在编译器已经意识到了这一点 – 但它不是一个实际定义的types。 编译器可以计算出寻址 – 但是这不是它打算如何使用的原因,因为我将暂时显示。

使用这种forms的声明的人,必须始终把“结构”实际上每提及一次,因为它不是一个官方的新types。

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

 typedef struct { field_1; ... }myStruct; 

现在它是一个实际的types,使用时可以在'myStruct'中使用,而不必用'struct'这个单词加上它。

如果你想要一个指向该结构的指针variables,那么包含一个辅助标签:

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

现在你有一个指向该结构的指针variables,自定义它。

前瞻性宣言 –

现在,这是一些花哨的东西,前进声明如何工作。 如果你想创build一个引用自己的types,比如链接列表或者队列元素,你必须使用前向声明。 编译器不考虑定义的结构,直到它到达最后的分号,所以它只是在该点之前声明。

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

现在,编译器知道虽然它不知道整个types是什么,但仍然可以使用前向引用来引用它。

请正确声明并键入你的结构。 其实有一个原因。

在后面的例子中,当使用结构时,你省略了struct关键字。 所以在你的代码中,你可以写:

 myStruct a; 

代替

 struct myStruct a; 

这样可以节省一些打字的时间,而且可以更具可读性,但这是一个有趣的问题