Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/batch-file/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 如何查找循环依赖项?_C++ - Fatal编程技术网

C++ 如何查找循环依赖项?

C++ 如何查找循环依赖项?,c++,C++,有人能给我推荐一个查找循环依赖项的工具吗?我尝试了一个项目的图表,但它有数百个头文件,所以很难找到它们 我用循环依赖的含义编辑了这篇文章: 文件A.h有一个包含“B.h”的防护装置 文件B.h有一个#include“a.h”防护装置 谢谢。根据您的问题,您正在处理大量头文件。一个解决办法是, 如果从头文件中删除方法定义,并让类仅包含方法声明和变量声明/定义。方法定义应该放在.cpp文件中(就像最佳实践指南所说的那样) //A.h #如果没有 #定义一个 乙级;; 甲级 { 国际价值; B*

有人能给我推荐一个查找循环依赖项的工具吗?我尝试了一个项目的图表,但它有数百个头文件,所以很难找到它们

我用循环依赖的含义编辑了这篇文章:

  • 文件A.h有一个包含“B.h”的防护装置
  • 文件B.h有一个#include“a.h”防护装置

谢谢。

根据您的问题,您正在处理大量头文件。一个解决办法是, 如果从头文件中删除方法定义,并让类仅包含方法声明和变量声明/定义。方法定义应该放在.cpp文件中(就像最佳实践指南所说的那样)

//A.h
#如果没有
#定义一个
乙级;;
甲级
{ 
国际价值;
B*_B;
公众:
A(int-val);
无效收进(B*B);
作废打印();
}; 
#恩迪夫
//B.h
#ifndef B_H
#定义B_H
甲级;
B类
{ 
双重价值;
A*_A;
公众:
B(双val);
无效刚毛(A*A);
作废打印();
}; 
#恩迪夫
//A.cpp
#包括“A.h”
#包括“B.h”
#包括
使用名称空间std;
A::A(int-val)
:_val(val)
{ 
} 
无效A::挫折(B*B)
{ 
_b=b;
cout您可以查询可能的或实际的包含周期,因为预处理指令实际上是一种要调试的语言

要了解实际循环,可以使用带有选项的预处理器cpp

-M  Instead of outputting the result of preprocessing, output a rule suitable for make describing the dependencies of the main source file...
或者更好

-MM Like -M but do not mention header files that are found in system header directories, nor header files that are included, directly or indirectly, from such a header.

当发现一个循环时,嵌套深度溢出将出现错误,使用-MF指定的输出将有助于发现问题

要了解可能的循环,递归访问源文件的近似分析应该很容易实现,使用映射跟踪包含的文件

编辑:这里是一个用于这种近似分析的程序草图

#include <set>
#include <vector>
#include <string>
#include <fstream>
#include <cstdlib>
#include <iostream>
#include <iterator>
#include <algorithm>
#include <stdexcept>

#include <boost/foreach.hpp>
#include <boost/filesystem.hpp>
#include <boost/program_options.hpp>

using namespace std;
using namespace boost;
using namespace boost::filesystem;
using namespace boost::program_options;

struct inclusions
{
    inclusions(int argc, char **argv)
    {
        options_description ops("detect_loops usage");
        ops.add_options()
             ("include,I", value< vector<string> >(), "search paths")
             ("file,F",    value< string >(),         "file to be analyzed");
        variables_map vm;
        store(parse_command_line(argc, argv, ops), vm);
        notify(vm);

        path start = locate(vm["file"].as<string>());
        simstack.push_back(start);

        // file directory is always search start
        include_paths.push_back(start.parent_path());

        if (vm.count("include"))
        {
            vector<string> s = vm["include"].as< vector<string> >();
            copy(s.begin(), s.end(), back_inserter(include_paths));
        }

        scan_includes();
    }

    typedef vector<path> t_paths;
    t_paths include_paths;

    t_paths simstack;

    typedef vector<t_paths> t_cycles;
    t_cycles cycles;

    set<path> analyzed;

    path locate(string file)
    {
        path p(file);
        if (exists(p))
            return p;
        BOOST_FOREACH(path i, include_paths)
        {
            path q = i / p;
            if (exists(q))
                return q;
        }
        throw domain_error(file + " not fund");
    }

    void scan_includes()
    {
        path c = simstack.back();
        if (analyzed.find(c) != analyzed.end())
            return;

        ifstream f(c.string());
        string l;
        while (getline(f, l))
        {
            char included[256 + 1];
            if (sscanf(l.c_str(), " # include \"%256[^\"]\"", included) == 1)
            {
                path p = locate(included);

                // check loops before recurse
                t_paths::iterator g = find(simstack.begin(), simstack.end(), p);
                if (g != simstack.end())
                {
                    t_paths loop(g, simstack.end());
                    loop.push_back(p);
                    cycles.push_back(loop);
                }
                else
                {
                    simstack.push_back(p);
                    scan_includes();
                    simstack.pop_back();
                }
            }
        }

        analyzed.insert(c);
    }
};

int main_detect_loops(int argc, char **argv)
{
    try
    {
        inclusions i(argc, argv);
        BOOST_FOREACH(inclusions::t_paths p, i.cycles)
        {
            copy(p.begin(), p.end(), ostream_iterator<path>(cout, ","));
            cout << endl;
        }
        return 0;
    }
    catch(const std::exception &e)
    {
        cerr << e.what() << endl;
        return 1;
    }
}
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
使用名称空间std;
使用名称空间boost;
使用名称空间boost::filesystem;
使用名称空间boost::program_选项;
结构包裹体
{
内含物(整数argc,字符**argv)
{
选项描述操作(“检测循环使用”);
操作.添加选项()
(“包括,I”,值(),“搜索路径”)
(“文件,F”,值(),“要分析的文件”);
变量映射vm;
存储(解析命令行(argc、argv、ops)、vm);
通知(vm);
path start=locate(vm[“file”].as());
simstack.向后推(开始);
//文件目录始终是搜索开始
包括路径。向后推(start.parent路径());
if(vm.count(“include”))
{
向量s=vm[“包括”]。如();
复制(s.begin()、s.end()、back_插入器(包括_路径));
}
扫描包括();
}
typedef向量t_路径;
t_路径包括t_路径;
图坦克;
typedef向量t_循环;
t_循环;
集合分析;
路径定位(字符串文件)
{
路径p(文件);
如果(存在(p))
返回p;
BOOST\u FOREACH(路径i,包括路径)
{
路径q=i/p;
如果(存在(q))
返回q;
}
抛出域_错误(文件+“非资金”);
}
无效扫描包括()
{
路径c=simstack.back();
if(analysisd.find(c)!=analysisd.end())
返回;
ifstream f(c.string());
字符串l;
while(getline(f,l))
{
字符包括[256+1];
如果(sscanf(l.c_str(),“#include\%256[^\“]\”,include)=1)
{
路径p=定位(包括);
//在递归之前检查循环
迭代器g=find(simstack.begin(),simstack.end(),p);
如果(g!=simstack.end())
{
t_路径循环(g,simstack.end());
环。推回(p);
循环。推回(循环);
}
其他的
{
simstack.推回(p);
扫描包括();
simstack.pop_back();
}
}
}
2.插入(c);
}
};
int main_detect_循环(int argc,char**argv)
{
尝试
{
包裹体i(argc,argv);
BOOST_FOREACH(包含::t_路径p,i循环)
{
复制(p.begin(),p.end(),ostream_迭代器(cout,“,”));

cout我找到了一种获取循环依赖关系的方法:

  • 使用Perl脚本生成一个描述#包含依赖关系定向图的点文件

    ./cinclude2dot.pl--src path_to_include_dir graph.dot

  • 将有向图分解为强连通组件(循环依赖):

    sccmap-v graph.dot


  • 什么?我可以考虑各种含义之间的循环依赖性。请详细说明一下。谢谢你的回答,但是我不能修改代码。我只需要知道哪些文件具有循环依赖性。A.H包括B.H和B.H包括A.H。在C++中,这是不允许的,因为它们会反复地相互牵连,导致EnDL。ess loop.it's will a ternitythy'-MM'方法只有在头文件没有包含保护的情况下才有效,因此它在实践中永远不起作用include2dot对我不起作用,因为我使用的是系统头,它找不到。如果有人有这个问题,请尝试:
    cinclude2dot--quotetypes quote--src path_to_include_dir graph.dot
     --quoteType quote
    使其仅使用
    #包含使用“”的
    指令,或仅使用项目本地的指令。
    -MF file
           When used with -M or -MM, specifies a file to write the dependencies to.  If no -MF switch is given the preprocessor sends the rules to the same place it would have sent preprocessed output.
    
    #include <set>
    #include <vector>
    #include <string>
    #include <fstream>
    #include <cstdlib>
    #include <iostream>
    #include <iterator>
    #include <algorithm>
    #include <stdexcept>
    
    #include <boost/foreach.hpp>
    #include <boost/filesystem.hpp>
    #include <boost/program_options.hpp>
    
    using namespace std;
    using namespace boost;
    using namespace boost::filesystem;
    using namespace boost::program_options;
    
    struct inclusions
    {
        inclusions(int argc, char **argv)
        {
            options_description ops("detect_loops usage");
            ops.add_options()
                 ("include,I", value< vector<string> >(), "search paths")
                 ("file,F",    value< string >(),         "file to be analyzed");
            variables_map vm;
            store(parse_command_line(argc, argv, ops), vm);
            notify(vm);
    
            path start = locate(vm["file"].as<string>());
            simstack.push_back(start);
    
            // file directory is always search start
            include_paths.push_back(start.parent_path());
    
            if (vm.count("include"))
            {
                vector<string> s = vm["include"].as< vector<string> >();
                copy(s.begin(), s.end(), back_inserter(include_paths));
            }
    
            scan_includes();
        }
    
        typedef vector<path> t_paths;
        t_paths include_paths;
    
        t_paths simstack;
    
        typedef vector<t_paths> t_cycles;
        t_cycles cycles;
    
        set<path> analyzed;
    
        path locate(string file)
        {
            path p(file);
            if (exists(p))
                return p;
            BOOST_FOREACH(path i, include_paths)
            {
                path q = i / p;
                if (exists(q))
                    return q;
            }
            throw domain_error(file + " not fund");
        }
    
        void scan_includes()
        {
            path c = simstack.back();
            if (analyzed.find(c) != analyzed.end())
                return;
    
            ifstream f(c.string());
            string l;
            while (getline(f, l))
            {
                char included[256 + 1];
                if (sscanf(l.c_str(), " # include \"%256[^\"]\"", included) == 1)
                {
                    path p = locate(included);
    
                    // check loops before recurse
                    t_paths::iterator g = find(simstack.begin(), simstack.end(), p);
                    if (g != simstack.end())
                    {
                        t_paths loop(g, simstack.end());
                        loop.push_back(p);
                        cycles.push_back(loop);
                    }
                    else
                    {
                        simstack.push_back(p);
                        scan_includes();
                        simstack.pop_back();
                    }
                }
            }
    
            analyzed.insert(c);
        }
    };
    
    int main_detect_loops(int argc, char **argv)
    {
        try
        {
            inclusions i(argc, argv);
            BOOST_FOREACH(inclusions::t_paths p, i.cycles)
            {
                copy(p.begin(), p.end(), ostream_iterator<path>(cout, ","));
                cout << endl;
            }
            return 0;
        }
        catch(const std::exception &e)
        {
            cerr << e.what() << endl;
            return 1;
        }
    }