为什么我们应该在C中经常输入一个结构体?
我看过很多程序,包括下面的结构
typedef struct
{
int i;
char k;
} elem;
elem user;
为什么需要这么频繁? 任何特定原因或适用区域?
正如Greg Hewgill所说,typedef意味着您不必再遍布整个地方写struct
。 这不仅可以节省击键次数,还可以使代码更清洁,因为它提供了更多的抽象。
东西喜欢
typedef struct {
int x, y;
} Point;
Point point_new(int x, int y)
{
Point a;
a.x = x;
a.y = y;
return a;
}
如果您不需要在整个地方看到“struct”关键字,就会变得更清晰,它看起来更像是您的语言中实际上有一种称为“Point”的类型。 其中,在typedef
,我猜是这样。
另外请注意,尽管您的示例(和我的)省略了命名struct
本身,但实际命名它对于您想要提供不透明类型时也很有用。 然后你可以在头文件中找到这样的代码,例如:
typedef struct Point Point;
Point * point_new(int x, int y);
然后在实现文件中提供struct
声明:
struct Point
{
int x, y;
};
Point * point_new(int x, int y)
{
Point *p;
if((p = malloc(sizeof *p)) != NULL)
{
p->x = x;
p->y = y;
}
return p;
}
在后一种情况下,由于其声明对头文件的用户是隐藏的,因此不能返回按值的点。 例如,这是一项在GTK +中广泛使用的技术。
更新请注意,还有一些高度重视的C项目,其中使用typedef
来隐藏struct
被认为是一个坏主意,Linux内核可能是最知名的这样的项目。 有关Linus愤怒的单词,请参阅Linux Kernel CodingStyle文档的第5章。 :)我的观点是,这个问题中的“应该”可能不是一成不变的。
有多少人弄错了,真是太神奇了。 请不要在C中使用typedef结构,它会不必要地污染已经在大型C程序中受到污染的全局名称空间。
而且,没有标签名称的typedef'd结构是造成头文件之间不必要的排序关系的主要原因。
考虑:
#ifndef FOO_H
#define FOO_H 1
#define FOO_DEF (0xDEADBABE)
struct bar; /* forward declaration, defined in bar.h*/
struct foo {
struct bar *bar;
};
#endif
有了这样一个定义,不使用typedef,compiland单元可以包含foo.h以获得FOO_DEF
定义。 如果它不试图取消引用foo
结构的'bar'成员,那么将不需要包含“bar.h”文件。
此外,由于标签名称和成员名称之间的名称空间不同,因此可以编写非常易读的代码,例如:
struct foo *foo;
printf("foo->bar = %p", foo->bar);
由于命名空间是独立的,因此命名与它们的结构标记名称一致的变量没有冲突。
如果我必须维护你的代码,我将删除你的typedef结构。
来自Dan Saks的一篇旧文章(http://www.ddj.com/cpp/184403396?pgno=3):
命名结构的C语言规则有点古怪,但它们非常无害。 然而,当扩展到C ++中的类时,这些相同的规则对于错误爬行没有什么影响。
在C中,名字出现在
struct s
{
...
};
是一个标签。 标签名称不是类型名称。 鉴于上面的定义,声明如
s x; /* error in C */
s *p; /* error in C */
在C中是错误的。你必须把它们写成
struct s x; /* OK */
struct s *p; /* OK */
联合和枚举的名称也是标签而不是类型。
在C中,标签不同于其他所有名称(对于函数,类型,变量和枚举常量)。 C编译器在符号表中维护标记,在概念上如果不是与包含所有其他名称的表在物理上分离的话。 因此,C程序有可能在相同范围内同时使用同一个拼写的标记和另一个名称。 例如,
struct s s;
是一个有效的声明,它声明了struct s类型的变量。 这可能不是好的做法,但C编译器必须接受它。 我从来没有看到为什么C这样设计的理由。 我一直认为这是一个错误,但它就是这样。
许多程序员(包括你的真正的)更喜欢将结构名称看作类型名称,所以他们使用typedef为标签定义一个别名。 例如,定义
struct s
{
...
};
typedef struct s S;
可以让你使用S代替结构体,如
S x;
S *p;
程序不能使用S作为类型和变量(或函数或枚举常量)的名称:
S S; // error
这很好。
结构体,联合体或枚举定义中的标记名是可选的。 许多程序员将结构定义折叠到typedef中,并完全免除标签,如下所示:
typedef struct
{
...
} S;
链接的文章还讨论了不需要typedef
的C ++行为如何导致细微的名称隐藏问题。 为了避免这些问题,这是一个好主意typedef
类和结构在C ++中,也是如此,尽管乍一看这似乎是不必要的。 在C ++中,使用typedef
,名称隐藏成为编译器告诉您的错误,而不是潜在问题的隐藏源。