这里主要介绍一下检查循环定义的结构体、联合体。是对成员中包含本身自己的结构体、联合体进行检查。所谓“成员中包含本身自己”,举例来讲,就是指下面这样的定义。java
struct point { struct point p; };
这里所说的“成员中包含本身自己”是指直接包含本身自己,经过指针来应用本身自己是没有问题的。例如刚才的例子,若是是下面这样的话就没有问题了。算法
struct point { struct point *ptr; };
刚才的例子中存在直接的循环定义,所以一眼就能看出来。还有以下所示的间接循环定义的状况,也须要注意。数组
struct point_x { struct point_y y; }; typedef struct point_x my_point_x; struct point_y { my_point_x x; };
上述例子中还夹杂着使用typedef 定义的类型,所以调查起来更为繁琐。ui
检查“循环定义的类型”的方法。进行这样的类型检查须要将类型定义的总体看成图(graph)来思考。spa
将类型的定义抽象为图时,能够将类型做为节点,将该类型对其余类型的引用做为边。例如结构体的定义,将该结构体的类型做为节点,向成员的类型的节点链接一条边。使用typedef 的状况下,将新定义的类型做为节点,向原来的类型节点引一条边。指针
再来看一个例子。如今假设有以下所示的定义。对象
struct st { struct point pnt; long len; }; typedef unsigned int uint; struct point { uint x; uint y; };
将上述定义转化为图,如图10.2 所示。blog
若是发生循环定义,那么在生成类型定义的图时,图中某处一定存在闭环。循环定义状况下的图如图10.3 所示。get
可见图中存在闭环。检查是否存在循环定义,只需检查类型定义的图中是否存在闭环便可。it
检测有向图中的闭环的算法
由于边存在方向性,因此类型定义的图属于有向图。要检测有向图中是否存在闭环,可使用以下算法。
1. 选择任意一个节点(类型)并标注为“查找中”
2. 沿着边依次访问全部与该节点相邻的节点
3. 若是访问到的节点没有标注任何状态,则将该节点标注为“查找中”;若是标注了“查找结束”,则不作任何处理,返回以前的节点;若是已经标注为“查找中”,则说明存在闭环
4. 从当前的节点重复步骤2 和3,若是已经没有可访问的相邻节点,则将该节点标注为“查找结束”,并沿原路返回
5. 按照上述流程对全部节点进行处理,若是查找过程当中没有遇到“查找中”状态的节点,就说明不存在闭环
上述算法中使用了“有向图的深度优先检索”来检测闭环。简单地说,该算法的概要就是“只要节点有未访问的相邻节点就试着访问,调查是否会回到原来的节点”。从算法执行过程当中的某一时刻来看,就是在为从起始节点到某一节点的路径上的全部节点标注上“查找中”的状态。
具体算法以下:
protected void checkRecursiveDefinition(Type t, ErrorHandler h) { _checkRecursiveDefinition(t, new HashMap<Type, Object>(), h); } static final protected Object checking = new Object(); static final protected Object checked = new Object(); /*结构体、联合体的循环定义检查 * 结构体、联合体、数组、typedef 所定义的类型之外的类型只有整数类型和指针,所以除 了上述4 个类型之外,其余状况下都不可能出现边。包含某类型的指针的状况下,由于不会产 生循环依赖,因此不会有问题。 算法说明中的“标注状态”的实现方式是“将Type 对象和它的状态做为一组保存在 Map 对象marks 中”,这是上述算法的重点。 */ protected void _checkRecursiveDefinition(Type t, Map<Type, Object> marks, ErrorHandler h) { /* * 若是t 的状态为“查找中”,输出错误并return */ if (marks.get(t) == checking) { h.error(((NamedType)t).location(), "recursive type definition: " + t); return; } /* * t 的状态为“查找结束” */ else if (marks.get(t) == checked) { return; } /* * 访问的节点尚未被标注状态。 * 将t 标注为“查找中”, * 访问全部和t 相邻的节点(调用_checkRecursiveDefinition), * 将t 标注为“查找结束”。 */ else { marks.put(t, checking); if (t instanceof CompositeType) { CompositeType ct = (CompositeType)t; for (Slot s : ct.members()) { _checkRecursiveDefinition(s.type(), marks, h); } } else if (t instanceof ArrayType) { ArrayType at = (ArrayType)t; _checkRecursiveDefinition(at.baseType(), marks, h); } else if (t instanceof UserType) { UserType ut = (UserType)t; _checkRecursiveDefinition(ut.realType(), marks, h); } marks.put(t, checked); } }