转发声明一种类型 – 这背后的原因是什么
/* Forward declare a type "point" to be a struct. */ typedef struct point point; /* Declare the struct with integer members x, y */ struct point { int x; int y; };
你能解释一下前方宣布背后的原因吗?
我注意到没有人真正回答过你问过的问题
向前声明类型的原因是什么?
答案是:C的设计使得它可以通过从上到下读取每个文件来编译。 考虑像C#这样的语言:
class C { B b; } class B { C c; }
请注意,如果编译器从上到下,编译器会在知道B
是什么之前到达类型B
的字段。 实际上,C#编译器从上到下不会读取整个文件。 它会对每个文件进行多次传递,并随着时间的推移建立信息。
现在假设您想编写一个C#编译器,它可以解析上面的程序而不需要多次传递。 不知何故,你必须在遇到字段b
之前告诉编译器有一个名为B
的类型。 但我们不能只将class B
class C
移到class C
class B
之前,因为这会再次产生同样的问题,这次是用C
!
在我们想象中的一次性C#版本中你可能会说你可以解决这个问题:
class B; // Tell the compiler that B will be defined later. class C { B b; } class B { C c; }
你去吧 当编译器到达B b
它知道B
是稍后定义的类。 B
已向前宣布 。
由于C#总是使用多遍方法,因此不需要这个技巧。 但是C的设计者确实需要单通道方法,因此它们需要前向声明的冗余。
这种单程方法旨在使机器具有几K内存并以每秒几千个周期运行的那一天更容易编译; 相比之下,C#的多次扫描方法每次构建复杂的数据结构都很昂贵,并且在速度和内存受限的机器上很难实现。
当然,我们当然拥有数万亿字节内存的机器(记住, 内存是磁盘空间 ; RAM只是磁盘上的缓存!)每秒运行数十亿个周期,但我们仍然不得不使用技术来制作编者在20世纪70年代的生活更加轻松。 这就是你使用C时的情况。
typedef struct point point; struct point { int x; int y; point *next; /* Could be used */ };
VS
// typedef struct point point; struct point { int x; int y; point *next; /* error: unknown type name 'point' */ };
什么是typedef?
typedef的目的是从更基本的机器类型中形成复杂类型,并为这种组合分配更简单的名称。 它们最常用于标准声明繁琐,可能令人困惑或可能因实现而异。
所以typedef struct point point;
不是你假设的前瞻性声明。 它将struct point
命名为point
,因此无论何时稍后写入point
,它都将引用struct point
。
那么现在,您可以将变量声明为point p;
而不是struct point p;
。
这不是一个point
的前向声明,这是它的typedef
* 。 typedef
让你写
point p;
代替
struct point p;
您的代码中未使用前向声明效果。 但是,使用typedef
,您可以在point
结构的声明中开始使用point
作为类型名称,而不是struct
标记。
实现相同效果的更常见方法是组合定义和typedef
,如下所示:
typedef struct point { int x; int y; } point;
* typedef
恰好是前向声明类型,但这是一个“副作用”。