定义结构的主要方法有两种:
struct triangle_s {
int a,b,c;
};
和
typedef struct triangle_s {
int a,b,c;
} triangle;
已经问过很多遍了,但是每个答案都是使用struct
变体时不必写typedef
这么多次。除了可以避免重复使用struct
关键字之外,还有其他实际区别吗?我听说您永远不要在C中使用typedef
变体,但没人说为什么。
答案 0 :(得分:6)
没有什么区别,typedef
删除了在变量声明前加上struct
的要求。
默认情况下是否建立typedef
结构是一场宗教战争,主要是由时间过长的人们进行的。在现有代码库中工作时,您应该执行任何编码标准或周围代码。对于您自己的个人代码,可以执行您喜欢的任何事情。
答案 1 :(得分:4)
没有“ typedef struct”这样的东西。
struct
尿素类型 struct
引入了一种结构,该结构是由一组命名成员组成的聚合数据类型。 (数组也是集合,但是它们由许多相同的成员组成,这些成员被索引。联合具有一组成员名称,但一次只能包含一个成员,因此它们不是集合。您可能不需要知道的。)
结构类型通常带有标签,因此实际的类型名称将类似于struct Triangle
。标签(Triangle
)与标识符不在同一名称空间中,因此使用也用于其他目的的标签没有问题。有些人喜欢在标签上附加_s
和_u
,表示它们分别是结构标签或联合标签,但这不是我的风格。我更喜欢在CamelCase中命名类型,对我来说,结构或联合标签代表着类型名。但是,当然,您可以自由使用自己的约定。
如果在程序中使用struct SomeTag
,则实际上是在声明一个结构,其标签为SomeTag
。您无需通过命名或描述结构的成员来填写声明,除非您需要在代码中引用它们。尚未声明其成员的结构称为 incomplete ,但仍可以用作指针类型的一部分,因为C标准保证所有结构指针的格式相同,无论结构的内容。 (这不能使它们互换,但这确实意味着编译器知道指针的大小。)一个从未定义其成员并且仅用作指针类型目标的结构称为不透明。
您可以通过添加成员声明块来完成结构的声明。所以
struct Triangle {
int a,b,c;
};
首先声明存在一个名称为struct Triangle
的结构,然后通过声明三个均为int
的命名成员来填充该结构的定义。
顺便说一下,联合声明和定义都非常相似。
结构定义可以在声明中使用,就像它是类型名称一样。或者换种说法,您可以为结构类型声明标签,立即填写字段,然后声明该类型的一个或多个变量:
struct Triangle { int a, b, c; } aTriangle, anotherTriangle;
这不是很常见的样式,但重要的是要知道语法是可能的。
最后,定义一个结构而不给它一个标签是合法的。无标签结构类型有一个怪癖:通常,没有两个结构类型可以具有相同的标签,但是所有无标签结构都是不同的。这意味着您可以声明一个实际上没有名称的结构类型,并且该结构类型不同于任何其他结构类型,甚至包括具有完全相同成员的结构类型。如果您只有一个实例(一个“单例”)的聚合,那可能会有点用,尽管我自己不会真的使用这种样式。但是经过一小段弯路之后,我们将看到此功能的另一种用途。
C类型名称可能会非常复杂,因为它们可以是逐段构建的。例如,const struct Triangle*[8]
是由八个成员组成的数组,每个成员都是指向不可修改的struct Triangle
的指针。 double (*)(const struct Triangle*[8])
是一个函数,它接受一个这样的数组作为参数(或更准确地说,由于数组到指针的衰减,它接受指向该数组的第一个元素的指针。但这在此无关紧要。 )
为使复杂类型更易于使用,C允许您为类型声明别名。别名用typedef
声明,否则看起来就像变量的声明。因此,例如,您可以使用
int
的变量
int someNumber;
,因此您可以使用
声明类型int
的别名
typedef int someType;
类似地,您可以使用
声明由八个指针组成的数组,这些数组指向const Triangle
元素
const Triangle* eightSlices[8];
以完全相同的方式,您可以使用以下方法声明此类数组的名称:
typedef const Triangle* EightSlices[8];
请注意,类型名称恰好与对象名称所处位置相同,该名称可以位于声明中间。
作为声明类型别名的简单示例,以下是您为结构类型声明别名的方法:
不完整的结构定义:
typedef struct Triangle Triangle;
或完整的结构定义:
typedef struct Triangle {
int a, b, c;
} Triangle;
或两者都分开(它们可以按任意顺序排列):
typedef struct Triangle Triangle;
struct Triangle {
int a, b, c;
};
请记住,结构标记和其他标识符(例如类型别名)位于不同的命名空间中,因此上述Triangle
的两种用法之间没有冲突。一些程序员认为有必要区分它们,即使其中一个只能在单词struct
之后立即使用,而另一个不能在单词struct
之后使用。其他人-我想您可以猜到我属于这一类人群-发现有意使用struct
一词来为两者故意使用相同的名称很方便,让我们知道它是否是类型别名或标签。 (而且,更常见的是,表明我们无意再次使用该标记。)
所以,回到我的开场白:
没有“ typedef struct”这样的东西。
没有。我们这里是声明和定义的非常普通的struct
。而且,我们有一个非常普通的类型别名,它为该struct
提供了备用名称。就是这样。
请注意,您可以为匿名类型(如无标签结构类型)指定别名,之后该类型将不再是匿名的。因此,有些人会忽略上述定义中的标签:
typedef struct {
int a, b, c;
} Triangle;
看起来很像上面提到的单例结构类型,但是由于它是一种类型,因此可以用来声明多个实例。但我实际上并不推荐这种样式。
每个人都有自己的样式首选项,其中大多数首选项都是有效的。我们大多数人都从事多个项目,并且由于每个项目都倾向于制定自己的样式指南,因此我们需要学习如何在不同项目中接受和使用不同样式。但是我认为我们大多数人都有自己最舒适的风格,当我们只是为自己编写代码时(或者当我们开始一个项目以吸引愿意遵守我们的同事的意图时),我们会恢复到这种风格。样式)。而我上面使用的是我的风格。
实际上,我尝试避免使用简明的声明+定义+别名语法,而是首选上面显示的两个声明版本:
typedef struct Triangle Triangle; /* type alias */
struct Triangle {
int a, b, c;
}; /* type definition */
之所以这样,是因为它允许我使用自引用成员定义类型,例如链表和树:
typedef struct TriangleList TriangleList;
struct TriangleList {
Triangle slice;
TriangleList* next;
};
(如果我不对类型进行前别名,则必须将成员声明为struct TriangleList* next;
,这使得对齐更加难看。)
有时候,我最终会得到相互引用的类型,在这种情况下,我需要在任何结构定义之前将别名收集在一起。这也可能是有利的,因为别名定义允许不透明地使用指向类型的指针,因此可以将其放置在根本不包含类型定义的公共标头中。
但仅此而已。随时忽略它。
答案 2 :(得分:2)
定义结构的主要方法有两种
不,只有一个:
struct triangle_s {
int a,b,c;
}
。这样的定义可以出现在多个上下文中,包括但不限于您所提供的两个,但重要的是要了解,您提供的两个语句不仅限于结构定义。
这个人的“更多”被认为有些空洞:
struct triangle_s { int a,b,c; };
它是结构类型和该类型的零个对象的声明。在右括号和分号之间有一个标识符列表,在这种情况下碰巧是空的。但是也可能是这样,例如:
struct triangle_s {
int a,b,c;
} triangle;
,它定义类型struct triangle_s
并声明triangle
作为该类型的对象。当然,这引出了第二个例子
typedef struct triangle_s { int a,b,c; } triangle;
与上一个完全相同,除了typedef
关键字指示声明的标识符是类型别名而不是对象标识符之外。同样,结构定义只是从struct
关键字到相关的右括号的一部分,请注意,typedef
可以用于声明 any 类型的别名,而不仅仅是结构。
除了可以避免重复重复操作 struct关键字?
您都可以使用struct triangle_s
定义,也可以使用任何形式的类型名称。在后一种情况下,您也可以将triangle
(在范围内的任何地方)用作struct triangle_s
的别名,以达到struct triangle_s
形式可以满足的所有目的,含义没有差异。这就是typedef
的重点。
我听说您永远不要使用typedef C中的变体,但没人说为什么。
有人反对第二种形式的就样式而言,其依据是在同一声明中将两种不同的事物混合在一起-结构类型的定义和别名的声明为了它。这种推论继续说明,如果您想要typedef
,则应该单独声明它:
struct triangle_s {
int a,b,c;
};
typedef struct triangle_s triangle;
不过,这又是代码风格问题,而不是功能问题。
围绕typedef
的使用还有其他一些风格要点,我个人对此深有感触。