检查头文件是否互相包含

来源:互联网 发布:南京哪些地方有mac专柜 编辑:程序博客网 时间:2024/04/30 20:36

头文件互相包含是一种非常见的问题,一旦工程很大,这样的问题比较难排除,特别是间接互相引用的时候。在项目的移植中常常会遇到这些问题,而sourceinsight中又无法查找头文件包含关系,所以特写了一个程序来解决此类问题。我还不知道是否有现成的解决办法,若有欢迎告知。

头文件是否互相包含实际上是查找有向图中是否有环路的问题。思路比较简单,可以定义一个图的结构。考虑到这是一个稀疏图,所以我借助stl中的mapvector来定义一个类似二维的表的结构,这样可以避免使用链表,而且运算效率也不会降低。图的遍历采用广度优先的办法,算法复杂度是O(n3),效率不是太高,但是由于是稀疏图,所以运行速度还是可以接受的。

 

相应的数据结构:

class Helper

{

private:

    //map<CString, set<CString> > m_HeadFiles;

    map<CString, vector<CString> > m_HeadFiles;

 

public:

    void OnProcess(const CString& strDir);

    void WriteInfo();

    int ProcessDir(const CString& strDir);

    int ProcessFile(const CString strPath, const CString& strFile);

    void Analyse();

};

算法如下:

程序递归查看目录下所有头文件,一旦发现某一行以”#include”开头,就认为它包含了某个头文件,并把这个被包含的头文件放到相应的vector中。

接下来分析间接包含的头文件,代码如下:

void Analyse()

{

    for (map<CString, vector<CString> >::iterator iter = m_HeadFiles.begin(); iter != m_HeadFiles.end(); ++iter)

    {

        vector<CString> vec;

        for (vector<CString>::iterator iter2 = iter->second.begin(); iter2 != iter->second.end(); ++iter2)

        {

            for (map<CString, vector<CString> >::iterator iter3 = m_HeadFiles.begin(); iter3 != iter; ++iter3)

            {

                if (*iter2 == iter3->first)

                {

                    vec.push_back(*iter2 + L"--");

                   for (vector<CString>::iterator iter4 = iter3->second.begin(); iter4 != iter3->second.end(); ++iter4)

                    {

                        if (*iter4 == L"--" || iter4->Find(L"--") >= 0)

                        {

                            vec.push_back(*iter4);

                            continue;

                        }

 

                        if (find(vec.begin(), vec.end(), *iter4) == vec.end())

                        {

                            vec.push_back(*iter4);

                        }

                    }

                    vec.push_back(L"--");

                }

            }

        }

        iter->second.insert(iter->second.end(), vec.begin(), vec.end());

    }

}

分析的效果如下表,表中含有相应的路径信息:

分析前

文件

a.h

b.h

c.h

包含的头文件

x.h

a.h ,c.h, d.h

b.h, d.h, y.h

分析后

文件

a.h

b.h

c.h

包含的头文件

x.h

a.h<, x.h, >, c.h , d.h

b.h<, a.h<, x.h, >, c.h, d.h, >, y.h

 

最后,在WriteInfo()函数中,判断当前的文件所包含的头文件中是否有自己,如果有则输出包含关系。

 

       类的使用很简单,只需要定义一个此类的对象,然后再调用它的OnProcess()并传入想要检验的工程所在的目录参数即可:

Helper helper;

helper.OnProcess(L”D://s795”);

 

程序中还有不少漏洞,比如#include如果出现在了注释或字符串中,或者在预处理的不同的开关中或者包含的头文件中有绝对或相对的地址等就会造成误判。程序中一定还有其它未知的错误,欢迎指出。

程序的运行结果如下:

 

 

图中比如“mywordsapp.h :->MyWordsApp_Fnc.h--->mywordsapp.h”表示文件mywordsapp.h中包含了MyWordsApp_Fnc.h头文件,而MyWordsApp_Fnc.h又包含了mywordsapp.h头文件,这样就会出现互相引用。

 

源码: