頭文件互相包含是一種非常見的問題,一旦工程很大,這樣的問題比較難排除,特別是間接互相引用的時候。在項目的移植中常常會遇到這些問題,而sourceinsight中又無法查找頭文件包含關係,所以特寫了一個程序來解決此類問題。我還不知道是否有現成的解決辦法,若有歡迎告知。
頭文件是否互相包含實際上是查找有向圖中是否有環路的問題。思路比較簡單,可以定義一個圖的結構。考慮到這是一個稀疏圖,所以我藉助stl中的map和vector來定義一個類似二維的表的結構,這樣可以避免使用鏈表,而且運算效率也不會降低。圖的遍歷採用廣度優先的辦法,算法複雜度是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頭文件,這樣就會出現互相引用。
源碼: