我见过许多由如下结构组成的程序
typedef struct
{
int i;
char k;
} elem;
elem user;
为什么如此频繁地需要它?有什么具体原因或适用领域吗?
我见过许多由如下结构组成的程序
typedef struct
{
int i;
char k;
} elem;
elem user;
为什么如此频繁地需要它?有什么具体原因或适用领域吗?
当前回答
正如Greg Hewgill所说,类型定义意味着你不再需要到处写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之后,我猜就是这个情况。
还要注意,虽然您的示例(和我的示例)省略了对结构体本身的命名,但当您希望提供不透明类型时,实际上对它进行命名也是有用的。然后你会在头文件中有这样的代码,例如:
typedef struct Point Point;
Point * point_new(int x, int y);
然后在实现文件中提供结构定义:
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;
}
在后一种情况下,您不能按值返回Point,因为它的定义对头文件的用户隐藏了。例如,这是GTK+中广泛使用的一种技术。
注意,在一些高度重视的C项目中,使用typedef来隐藏struct被认为是一个坏主意,Linux内核可能是最著名的这样的项目。关于Linus的愤怒言论,请参阅Linux内核编码风格文档的第5章。:)我的观点是,这个问题中的“应该”也许并不是一成不变的。
其他回答
使用typedef可以避免每次声明该类型的变量时都要写struct:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
正如Greg Hewgill所说,类型定义意味着你不再需要到处写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之后,我猜就是这个情况。
还要注意,虽然您的示例(和我的示例)省略了对结构体本身的命名,但当您希望提供不透明类型时,实际上对它进行命名也是有用的。然后你会在头文件中有这样的代码,例如:
typedef struct Point Point;
Point * point_new(int x, int y);
然后在实现文件中提供结构定义:
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;
}
在后一种情况下,您不能按值返回Point,因为它的定义对头文件的用户隐藏了。例如,这是GTK+中广泛使用的一种技术。
注意,在一些高度重视的C项目中,使用typedef来隐藏struct被认为是一个坏主意,Linux内核可能是最著名的这样的项目。关于Linus的愤怒言论,请参阅Linux内核编码风格文档的第5章。:)我的观点是,这个问题中的“应该”也许并不是一成不变的。
摘自Dan Saks的一篇旧文章(http://www.ddj.com/cpp/184403396?pgno=3):)
The C language rules for naming structs are a little eccentric, but they're pretty harmless. However, when extended to classes in C++, those same rules open little cracks for bugs to crawl through. In C, the name s appearing in struct s { ... }; is a tag. A tag name is not a type name. Given the definition above, declarations such as s x; /* error in C */ s *p; /* error in C */ are errors in C. You must write them as struct s x; /* OK */ struct s *p; /* OK */ The names of unions and enumerations are also tags rather than types. In C, tags are distinct from all other names (for functions, types, variables, and enumeration constants). C compilers maintain tags in a symbol table that's conceptually if not physically separate from the table that holds all other names. Thus, it is possible for a C program to have both a tag and an another name with the same spelling in the same scope. For example, struct s s; is a valid declaration which declares variable s of type struct s. It may not be good practice, but C compilers must accept it. I have never seen a rationale for why C was designed this way. I have always thought it was a mistake, but there it is. Many programmers (including yours truly) prefer to think of struct names as type names, so they define an alias for the tag using a typedef. For example, defining struct s { ... }; typedef struct s S; lets you use S in place of struct s, as in S x; S *p; A program cannot use S as the name of both a type and a variable (or function or enumeration constant): S S; // error This is good. The tag name in a struct, union, or enum definition is optional. Many programmers fold the struct definition into the typedef and dispense with the tag altogether, as in: typedef struct { ... } S;
这篇链接的文章还讨论了不需要类型定义的c++行为是如何导致微妙的名称隐藏问题的。为了防止这些问题,在c++中对类和结构进行类型定义也是一个好主意,尽管乍一看似乎没有必要。在c++中,有了类型定义,隐藏的名称就变成了编译器告诉你的错误,而不是潜在问题的隐藏来源。
让我们从最基本的开始,慢慢来。
下面是一个结构定义的例子:
struct point
{
int x, y;
};
这里的名称点是可选的。
结构可以在定义期间声明,也可以在定义之后声明。
在定义期间声明
struct point
{
int x, y;
} first_point, second_point;
在定义之后声明
struct point
{
int x, y;
};
struct point first_point, second_point;
现在,仔细注意上面的最后一种情况;如果您决定稍后在代码中创建该类型,则需要编写struct point来声明该类型的结构。
输入类型。如果您打算在稍后使用相同的蓝图在程序中创建新的Structure (Structure是自定义数据类型),那么在定义过程中使用typedef可能是一个好主意,因为您可以节省一些输入。
typedef struct point
{
int x, y;
} Points;
Points first_point, second_point;
在命名自定义类型时要注意一点
没有什么可以阻止您在自定义类型名称的末尾使用_t后缀,但POSIX标准保留使用后缀_t来表示标准库类型名称。
在C99中,typedef是必需的。它已经过时了,但是很多工具(比如HackRank)使用c99作为它的纯C实现。这里需要typedef。
我不是说他们应该改变(也许有两个C选项),如果要求改变,我们这些在网站上学习面试的人将是SOL。