为什么我们要在C中如此频繁地键入定义结构?

为什么我们要在C中如此频繁地键入定义结构?,c,struct,typedef,C,Struct,Typedef,我看过许多由如下结构组成的程序 typedef struct { int i; char k; } elem; elem user; 为什么经常需要它?任何特定原因或适用区域?使用typedef避免每次声明该类型的变量时都必须写入struct: struct elem { int i; char k; }; elem user; // compile error! struct elem user; // this is correct 正如Greg Hewgill所

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

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

elem user;

为什么经常需要它?任何特定原因或适用区域?

使用
typedef
避免每次声明该类型的变量时都必须写入
struct

struct elem
{
 int i;
 char k;
};
elem user; // compile error!
struct elem user; // this is correct

正如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
之后,我想是这样的

还要注意的是,虽然您的示例(和我的示例)忽略了对
结构本身进行命名,但实际上,当您希望提供不透明类型时,对其进行命名也很有用。然后在标题中有如下代码,例如:

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;
}
在后一种情况下,您不能返回逐点值,因为它的定义对头文件的用户是隐藏的。例如,这是一种广泛应用的技术

更新注意,也有一些备受推崇的C项目,其中使用
typedef
隐藏
struct
被认为是一个坏主意,Linux内核可能是最著名的此类项目。请参阅第5章,了解Linus的愤怒言论。:)我的观点是,问题中的“应该”可能毕竟不是一成不变的。

您(可选)给结构的名称称为标记名,正如已经指出的,它本身不是一个类型。要获取该类型,需要结构前缀

GTK+,我不确定TAGNEX使用的任何东西都与Type类型一样,通常是TyWupe,所以在C++中,可以识别并省略Stutt关键字,并使用TAGNOTY作为类型名:


    struct MyStruct
    {
      int i;
    };

    // The following is legal in C++:
    MyStruct obj;
    obj.i = 7;

来自Dan Saks()的一篇旧文章:


C语言命名规则 结构有点古怪,但是 它们是无害的。但是,什么时候? 扩展到C++类中,那些 规则为bug打开了小裂缝 爬过去

在C语言中,名称s出现在

struct s
    {
    ...
    };
这是一个标签。标记名不是类型 名称根据上述定义, 声明,如

s x;    /* error in C */
s *p;   /* error in C */
是C语言中的错误。您必须编写它们 作为

联合和枚举的名称 也是标记而不是类型

在C语言中,标记不同于所有其他标记 名称(用于函数、类型、, 变量和枚举常量)。 C编译器在符号中维护标记 表,如果不是 身体上与桌子分开 包含所有其他名称。因此, 一个C程序有可能 一个标签和另一个带有 同一范围内的相同拼写。 比如说,

struct s s;
是一个有效的声明,声明 类型为struct s的变量s。可能 不是很好的实践,但是C编译器 我们必须接受它。我从来没有见过一只猫 C为什么设计成这样的基本原理 对。我一直认为这是一个好消息 错了,但它就在那里

许多程序员(包括你的) 确实)更愿意考虑结构名称 作为类型名,因此它们定义别名 对于使用typedef的标记。对于 例如,定义

struct s
    {
    ...
    };
typedef struct s S;
允许您使用S代替结构S, 如

程序不能使用S作为的名称 类型和变量(或 函数或枚举常量):

这很好

结构、联合或组合中的标记名 枚举定义是可选的。许多的 程序员折叠结构定义 输入typedef并免除 全部标记,如:

typedef struct
    {
    ...
    } S;


链接文章还讨论了不要求<代码> TyPufF的C++行为如何引起微妙的名称隐藏问题。为了防止这些问题,在C++中编写代码> TyPulf是您的一个好主意,尽管乍看起来,它似乎是多余的。在C++中,使用<代码> TyPulfF名称隐藏成为编译器告诉您的错误,而不是潜在问题的隐藏来源。

< P> > TyEndof枚举和结构的另一个好原因是:
enum EnumDef
{
  FIRST_ITEM,
  SECOND_ITEM
};

struct StructDef
{
  enum EnuumDef MyEnum;
  unsigned int MyVar;
} MyStruct;
注意结构(EnuumDef)中EnumDef的输入错误吗?它编译时没有错误(或警告),并且是正确的(取决于C标准的文字解释)。问题是我刚刚在结构中创建了一个新的(空的)枚举定义。我没有(按预期)使用前面的定义

对于typdef,类似类型的输入错误会导致使用未知类型的编译器错误:

typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
我主张总是键入定义结构和枚举


这不仅是为了节省一些输入(不是双关语),而且因为它更安全。

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

因此:

结构b的扩展如下:

struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}
因此,在编译时,它在堆栈上演变为: b: 国际ai int i int j

这也是为什么在一个不能终止的声明循环中很难有自引用结构、C预处理器循环的原因

typedef是类型说明符,这意味着只有C编译器处理它,它可以像他所希望的那样优化汇编代码实现。它也不像Pro处理器那样用结构笨拙地扩展PAR成员,而是使用更复杂的参考构造算法,因此构造如下:

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

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;
是许可的,功能齐全。此实现还允许访问编译器类型转换,并在执行线程离开应用程序字段时消除一些错误影响
typedef 
{
  FIRST_ITEM,
  SECOND_ITEM
} EnumDef;

typedef struct
{
  EnuumDef MyEnum; /* compiler error (unknown type) */
  unsigned int MyVar;
} StructDef;
StrructDef MyStruct; /* compiler error (unknown type) */
struct a
{
   int i;
};

struct b
{
   struct a;
   int i;
   int j;
};
struct b
{
    struct a
    {
        int i;
    };
    int i;
    int j;
}
typedef struct a A; //anticipated declaration for member declaration

typedef struct a //Implemented declaration
{
    A* b; // member declaration
}A;
#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
struct foo *foo;

printf("foo->bar = %p", foo->bar);
vps_t a;
struct virtual_container *a;
typedef unsigned long myflags_t;
typedef struct Tag{
...members...
}Type;
typedef Type *Type_ptr;
Type_ptr var1, var2;
struct Tag *myTagType1, myTagType2;
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;
...
}
#define X char[10] or
typedef char Y[10]
unsigned X x; but not
unsigned Y y;
struct bar;
struct foo;

struct foo {
    struct bar *b;
};

struct bar {
    struct foo *f;
};
typedef struct foo foo_t;
typedef struct bar bar_t;
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);

}
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);

}
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;
typedef struct point
  {
    int x, y;
  } Points;

Points first_point, second_point;