自动生成C代码的方法:从头文件开始

8
我想生成一个头文件中定义的过程的空实现。理想情况下,它们应该对指针返回NULL,对整数返回0等,并且在理想的世界中,还应该打印到stderr中调用的函数。
这样做的动机是需要实现一个包装器,将复杂现有API(头文件)的子集适配到另一个库中。只需委派API中的少数程序,但不清楚哪些程序。因此,我希望使用迭代方法,在运行自动生成的包装器时查看所调用的内容,使用委派实现它,并重复此操作。
我已经看到了Automatically generate C++ file from header? ,但回答似乎是针对C++的。
因此,对于需要简单明了地说明问题的人,如何在给定头文件的情况下自动化生成这样的实现?我更喜欢现有工具-我目前最简单的解决方案是使用pycparser。
更新:谢谢大家。两个答案都很好。同时也发布了我的当前hack。

现在我看到你并没有真正提出问题,但我猜你是在寻找一个现有的工具来完成这个任务?不幸的是,我不知道任何这样的工具,但这听起来足够基础,可以使用快速的Python(或任何其他高级语言)实现来解决它。 - Jite
我已经澄清了问题。是的,我可以编写一个程序来实现这个。但这并不是一件简单的事情 - 比如说,它需要一个像样的解析器。头文件足够大,而且足够复杂,一个临时的基于正则表达式的解决方法会导致耗时混乱。 - andrew cooke
你好,这个过程需要容易重复吗?例如,当API有新版本发布时,您是否希望能够更新存根实现? - OlduwanSteve
哦,好问题。不,那不是必要的(如果这样做的话会更好,但我可以看到它会使事情变得非常复杂,而且这是一个标准API,不太可能发生重大改变)。 - andrew cooke
如果你对脚本编程很熟悉的话,也许可以自己编写一个工具?这看起来是一个相对简单的任务,可以使用正则表达式来处理... - RonaldBarzell
这应该很容易,只需右键点击 -> 源代码 -> 在 Eclipse 中生成 getter 和 setter。除此之外,您可以寻找一些微型 C 编译器学生示例并稍微构建它。 - Shark
3个回答

2

因此,我将EA提议标记为“答案”,因为我认为这可能是一般情况下最好的想法。尽管我认为在TDD方法中,CMock建议可以很好地工作,其中库开发是由测试失败驱动的,并且我可能会尝试那种方法。但是现在,我需要一个更快+更脏的方法,以交互方式运行(问题中的库是另一个交互式程序的动态加载插件,我正在尝试反向工程API调用序列...)

所以,我最终做的是编写了一个调用pycparse的Python脚本。如果对其他人有帮助,我将在此处包含它,但它不是通用的(例如,假设所有函数都返回int,并且有一个避免typedef内部的func defs的hack)。

from pycparser import parse_file
from pycparser.c_ast import NodeVisitor


class AncestorVisitor(NodeVisitor):

    def __init__(self):
        self.current = None
        self.ancestors = []

    def visit(self, node):
        if self.current:
            self.ancestors.append(self.current)
        self.current = node
        try:
            return super(AncestorVisitor, self).visit(node)
        finally:
            if self.ancestors:
                self.ancestors.pop(-1)


class FunctionVisitor(AncestorVisitor):

    def visit_FuncDecl(self, node):
        if len(self.ancestors) < 3: # avoid typedefs
            print node.type.type.names[0], node.type.declname, '(',
            first = True
            for param in node.args.params:
                if first: first = False
                else: print ',',
                print param.type.type.names[0], param.type.declname,
            print ')'
            print '{fprintf(stderr, "%s\\n"); return 0;}' % node.type.declname


print '#include "myheader.h"'
print '#include <stdio.h>'
ast = parse_file('myheader.h', use_cpp=True)
FunctionVisitor().visit(ast)

1

注意:这是一个未经研究的答案,因为我个人没有任何经验。

我认为你可以尝试使用专为单元测试设计的模拟框架。其中一个示例是:cmock

项目页面建议它将从头文件生成代码。然后你可以拿取代码并对其进行调整。


这是一个有趣的想法,谢谢。我目前正在与C++作斗争,只是为了得到我想要的头文件格式,但我会更深入地思考这种方法。 - andrew cooke

1

UML建模工具能够在所选语言中生成默认实现。通常还支持导入源代码(包括C头文件)。您可以尝试导入您的头文件并从中生成源代码。我个人有使用Enterprise Architect的经验,它支持这两种操作。


啊,是的,EA可能会这样做(虽然不包括打印语句)。不过可能只在付费版本中才有,而且我已经好几年没有许可证了。我会去查一下的,谢谢。 - andrew cooke
我相信也有免费的工具可以做这件事,可以问问谷歌。 - SomeWittyUsername
曾经免费的UML工具非常糟糕(我是EA的粉丝,只是没有客户需要UML),但现在可能已经改变了。我会去看看。 - andrew cooke

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接