我见过许多由如下结构组成的程序
typedef struct
{
int i;
char k;
} elem;
elem user;
为什么如此频繁地需要它?有什么具体原因或适用领域吗?
我见过许多由如下结构组成的程序
typedef struct
{
int i;
char k;
} elem;
elem user;
为什么如此频繁地需要它?有什么具体原因或适用领域吗?
当前回答
我认为typedef甚至不可能实现前向声明。使用struct, enum和union允许在依赖关系(知道)是双向的情况下转发声明。
风格: 在c++中使用typedef是很有意义的。在处理需要多个和/或变量参数的模板时,它几乎是必要的。typedef有助于保持命名的直直性。
在C编程语言中并非如此。typedef的使用通常没有任何目的,只会混淆数据结构的使用。由于只有{struct (6), enum (4), union(5)}个按键被用于声明一个数据类型,因此结构的别名几乎没有任何用处。数据类型是联合还是结构?使用简单的非类型定义声明可以让您立即知道它是什么类型。
请注意Linux是如何在编写时严格避免typedef带来的这种无意义的别名的。结果是一个极简主义和干净的风格。
其他回答
摘自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++中,有了类型定义,隐藏的名称就变成了编译器告诉你的错误,而不是潜在问题的隐藏来源。
使用typedef可以避免每次声明该类型的变量时都要写struct:
struct elem
{
int i;
char k;
};
elem user; // compile error!
struct elem user; // this is correct
Linux内核编码风格第5章给出了使用typedef的优点和缺点(主要是缺点)。
Please don't use things like "vps_t". It's a mistake to use typedef for structures and pointers. When you see a vps_t a; in the source, what does it mean? In contrast, if it says struct virtual_container *a; you can actually tell what "a" is. Lots of people think that typedefs "help readability". Not so. They are useful only for: (a) totally opaque objects (where the typedef is actively used to hide what the object is). Example: "pte_t" etc. opaque objects that you can only access using the proper accessor functions. NOTE! Opaqueness and "accessor functions" are not good in themselves. The reason we have them for things like pte_t etc. is that there really is absolutely zero portably accessible information there. (b) Clear integer types, where the abstraction helps avoid confusion whether it is "int" or "long". u8/u16/u32 are perfectly fine typedefs, although they fit into category (d) better than here. NOTE! Again - there needs to be a reason for this. If something is "unsigned long", then there's no reason to do typedef unsigned long myflags_t; but if there is a clear reason for why it under certain circumstances might be an "unsigned int" and under other configurations might be "unsigned long", then by all means go ahead and use a typedef. (c) when you use sparse to literally create a new type for type-checking. (d) New types which are identical to standard C99 types, in certain exceptional circumstances. Although it would only take a short amount of time for the eyes and brain to become accustomed to the standard types like 'uint32_t', some people object to their use anyway. Therefore, the Linux-specific 'u8/u16/u32/u64' types and their signed equivalents which are identical to standard types are permitted -- although they are not mandatory in new code of your own. When editing existing code which already uses one or the other set of types, you should conform to the existing choices in that code. (e) Types safe for use in userspace. In certain structures which are visible to userspace, we cannot require C99 types and cannot use the 'u32' form above. Thus, we use __u32 and similar types in all structures which are shared with userspace. Maybe there are other cases too, but the rule should basically be to NEVER EVER use a typedef unless you can clearly match one of those rules. In general, a pointer, or a struct that has elements that can reasonably be directly accessed should never be a typedef.
在'C'编程语言中,关键字'typedef'用于为某些对象(struct, array, function..enum类型)声明一个新名称。例如,我将使用struct-s。 在C语言中,我们经常在main函数之外声明一个struct。例如:
struct complex{ int real_part, img_part }COMPLEX;
main(){
struct KOMPLEKS number; // number type is now a struct type
number.real_part = 3;
number.img_part = -1;
printf("Number: %d.%d i \n",number.real_part, number.img_part);
}
每次我决定使用结构体类型时,我将需要这个关键字'struct 'something' name'。'typedef'将简单地重命名该类型,我可以在我的程序中随时使用这个新名称。所以我们的代码是:
typedef struct complex{int real_part, img_part; }COMPLEX;
//now COMPLEX is the new name for this structure and if I want to use it without
// a keyword like in the first example 'struct complex number'.
main(){
COMPLEX number; // number is now the same type as in the first example
number.real_part = 1;
number.img)part = 5;
printf("%d %d \n", number.real_part, number.img_part);
}
如果你有一些局部对象(结构,数组,有价值的),将在你的整个程序中使用,你可以简单地给它一个名字使用'typedef'。
正如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章。:)我的观点是,这个问题中的“应该”也许并不是一成不变的。