可视化C结构依赖项

问题描述 投票:5回答:3

在大型C项目中,有许多struct具有其他struct或指向它们的指针作为字段。我想创建一个有向图以显示“类型”之间的依赖关系。一个例子是

typedef struct javaStat {
    int idNo;
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
} ...

由此,我想生成一个DOT结构,看起来像

digraph {
    javaStat -> idIdentList
    javaStat -> typeModifiers
    javaStat -> symbol
}

或使用DOT速记:

digraph {
    javaStat -> {idIdentList typeModifiers symbol}
}

当然可以手动添加第一行和最后一行,所以主要问题是将结构引用转换为图形“指针”行。

此时,我对第一层解决方案感到满意,这意味着可以忽略更深层的嵌套。

我首先尝试了一个简单的grep struct *.h,它产生了一些可行的结果:

typedef struct javaStat {
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
typedef struct <next struct> {

这是一个简单的问题,几行Python可以解决,但是还有其他方便的解决方案,也许使用sedgrepawk及其弟兄?

编辑:我已经意识到我想要这样做的原因是因为我需要找到位于“结构树”基础上的一个或多个结构。

c struct dot
3个回答
2
投票

我将从在代码库上运行Doxygen开始。可以轻松配置它以创建结构的点图。正确解析所有这些信息并生成正确的输出会涉及足够的怪癖和极端情况,使用现有解决方案可以节省很多时间。


1
投票

Clang 9允许c文件的AST的JSON表示(在此question中找到)。可以进一步处理JSON AST以生成目标输出。

例如此Python脚本:

#clang_ast_to_dot.py
from jsonpath_rw_ext import parse;
import sys, json;

def extract_struct_name(fieldDefinition):
  return fieldDefinition["type"]["qualType"].replace("struct", "").replace("*", "").replace(" ","")

def is_struct_field(fieldDefinition, knownStructs):
  return (fieldDefinition["kind"] == "FieldDecl" and 
          ("struct " in fieldDefinition["type"]["qualType"] or 
           extract_struct_name(fieldDefinition) in knownStructs))


data = json.load(sys.stdin)

allStructs = {}

for structDef in parse('$.inner[?(@.kind=="RecordDecl")]').find(data):
    allStructs[structDef.value["name"]]=structDef.value

print("digraph {")
for name, structDescription in allStructs.items():
    print("    %s -> {%s}"
          % (name, ", ".join(extract_struct_name(field) for field in structDescription["inner"] if is_struct_field(field, allStructs))))
print("}")

称为:

clang -Xclang -ast-dump=json MyCFile.c | python clang_ast_to_dot.py

产生:

digraph {
    javaStat -> {idIdentList, typeModifiers, symbol}
}

当然,这是一个玩具示例,我确定它不适用于所有情况。


0
投票

对@gavinb答案的扩展,并举例说明。

具有具有EXTRACT_ALL = YESHAVE_DOT=YES的doxygen配置文件(对于更复杂的情况,将DOT_GRAPH_MAX_NODES =设置为适当的值并设置DOT_IMAGE_FORMAT = svg可能会有用;也可能是UML_LOOK = YES。] >

我用一个简单的例子:

typedef  struct idIdentList {
     int member;
};
typedef  struct typeModifiers {
     int member;
};
typedef  struct symbol {
     int member;
};
typedef  struct s1 {
     struct s2 member;
};
typedef  struct s2 {
     struct s3 member;
};
typedef  struct s3 {
     struct s4 member;
};
typedef  struct s4 {
     struct s5 member;
};
typedef  struct s5 {
     struct s6 member;
};
typedef  struct s6 {
     struct s6 member;
};
typedef struct javaStat {
    int idNo;
    struct idIdentList *className;
    struct typeModifiers *thisType;
    struct symbol thisClass;
    struct s1 member;
};

从中我得到:

enter image description here

[Doxygen没有完整的概述图,但是只需编写一些脚本就可以创建一个“超级结构”,例如(我也在这里添加了struct not_ref,这里没有多余的参考):]]

typedef struct super_script
{
  struct idIdentList a1;
  struct typeModifiers a2;
  struct symbol a3;
  struct s1 a4;
  struct s2 a5;
  struct s3 a6;
  struct s4 a7;
  struct s5 a8;
  struct s6 a9;
  struct javaStat a10;
  struct not_ref a11;
};

typedef struct not_ref
{
  int member;
};

结果:

enter image description here

当您设置DOT_CLEANUP = NO时,使用的dot文件将在html目录中可用

© www.soinside.com 2019 - 2024. All rights reserved.