我见过许多由如下结构组成的程序

typedef struct 
{
    int i;
    char k;
} elem;

elem user;

为什么如此频繁地需要它?有什么具体原因或适用领域吗?


当前回答

在'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'。

其他回答

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中定义结构类型,它不必要地污染全局命名空间,在大型C程序中,全局命名空间通常已经被严重污染。

此外,没有标记名的类型定义结构是头文件之间不必要的排序关系的主要原因。

考虑:

#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,编译单元可以包含foo.h来获得FOO_DEF定义。如果它不试图解引用foo结构体的'bar'成员,那么就不需要包含"bar.h"文件。

此外,由于标签名和成员名之间的名称空间是不同的,因此可以编写非常可读的代码,例如:

struct foo *foo;

printf("foo->bar = %p", foo->bar);

由于名称空间是分开的,因此在命名变量时与其struct标记名一致时不存在冲突。

如果我必须维护你的代码,我会删除你的类型定义结构。

一个有用的信息来源是《Expert C Programming》(第3章)。简单地说,在C语言中你有多个命名空间:标记、类型、成员名和标识符。Typedef为类型引入别名,并将其定位在标记命名空间中。也就是说,

typedef struct Tag{
...members...
}Type;

定义了两个东西。1)在标签命名空间中标记,2)在类型命名空间中键入。你可以同时使用myType和struct Tag myTagType。像struct Type myType或Tag myTagType这样的声明是非法的。此外,在这样的声明中:

typedef Type *Type_ptr;

定义一个指向类型的指针。如果我们声明:

Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;

那么var1,var2和myTagType1是指向Type的指针,而myTagType2不是。

在上面提到的书中,它提到对结构进行类型定义并不是很有用,因为它只是让程序员不用编写struct这个词。然而,像许多其他C程序员一样,我有一个反对意见。虽然有时会混淆一些名称(这就是为什么在像内核这样的大型代码库中不可取的原因),但当您想在C中实现多态性时,查看这里的详细信息会有很大帮助。例子:

typedef struct MyWriter_t{
    MyPipe super;
    MyQueue relative;
    uint32_t flags;
...
}MyWriter;

你可以:

void my_writer_func(MyPipe *s)
{
    MyWriter *self = (MyWriter *) s;
    uint32_t myFlags = self->flags;
...
}

因此,您可以通过强制转换通过内部结构(mpipe)访问外部成员(flags)。对我来说,强制转换整个类型比执行(struct MyWriter_ *) s;每次你想执行这样的功能。在这种情况下,简要引用是很重要的,特别是当你在代码中大量使用这种技术时。

最后,与宏相比,类型定义类型的最后一个方面是无法扩展它们。例如,你有:

#define X char[10] or
typedef char Y[10]

然后你可以声明

unsigned X x; but not
unsigned Y y;

对于结构体,我们并不关心这一点,因为它不适用于存储说明符(volatile和const)。

我认为typedef甚至不可能实现前向声明。使用struct, enum和union允许在依赖关系(知道)是双向的情况下转发声明。

风格: 在c++中使用typedef是很有意义的。在处理需要多个和/或变量参数的模板时,它几乎是必要的。typedef有助于保持命名的直直性。

在C编程语言中并非如此。typedef的使用通常没有任何目的,只会混淆数据结构的使用。由于只有{struct (6), enum (4), union(5)}个按键被用于声明一个数据类型,因此结构的别名几乎没有任何用处。数据类型是联合还是结构?使用简单的非类型定义声明可以让您立即知道它是什么类型。

请注意Linux是如何在编写时严格避免typedef带来的这种无意义的别名的。结果是一个极简主义和干净的风格。

在C语言中,struct/union/enum是由C语言预处理器处理的宏指令(不要与处理“#include”和other的预处理器混淆)

so :

struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};

结构b是这样展开的:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}

因此,在编译时,它在堆栈上的演变是这样的: b: int人工智能 int我 int j

这也是为什么在不能终止的déclaration循环中很难有自不同的结构,C预处理器循环。

typedef是类型说明符,这意味着只有C编译器处理它,它可以像他想要的那样优化汇编代码实现。它也不会像préprocessor那样愚蠢地使用par类型的成员,而是使用更复杂的引用构造算法,因此构造如下:

typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;

是允许的,功能齐全。当执行线程离开初始化函数的应用程序字段时,这个实现还允许访问编译器类型转换,并删除一些bug影响。

这意味着在C中,typedef比单独的结构体更接近c++类。