为什么我们要在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;