在运行时将.h头文件解析为C#数据结构

4
我正在尝试编写一个C#库来操作我的C/C++头文件。我想能够读取和解析头文件,并在C#中操纵函数原型和数据结构。由于所有的#ifdef等代码分支,我试图避免编写C解析器。
我尝试了使用EnvDTE,但找不到合适的文档。有什么办法可以做到吗?
编辑 - 谢谢你们的答案……以下是有关我的项目的更多细节:我正在使用调试API编写类似于ptrace的Windows工具,它使我能够跟踪已经编译的二进制文件并查看调用哪些Windows API。我还想知道每个调用中给定的参数以及给定的返回值,因此我需要知道API的定义。我也想知道自己库的定义(因此,采用了头文件解析方法)。我想到了3种解决方案: * 解析头文件 * 解析PDB文件(我使用DIA SDK编写了一个原型,但不幸的是,符号PDB只包含有关API的一般信息,而不是带有参数和返回值的真实原型) * 在MSDN在线库上爬行(自动或手动)
有没有更好的方法来在C#中运行时获取Windows API和我的库的名称和类型?

4
不要这样做,无论你为什么要这样做:你都是错的。除非你正在编写词法分析器或解析器生成器,否则你不需要问这种问题。 - dtech
我想不到其他方法从我的代码库中获取原型(我需要它用于一些测试环境/模糊测试器)。 - drzoidberg
1
此外,你正在犯经典的"XY问题"错误:http://meta.stackexchange.com/questions/66377/what-is-the-xy-problem - dtech
2
你一直在解释我做错了什么,但没有给出真正的答案... 我选择这种方法有我的理由,而你的回答并不是很有帮助。 - drzoidberg
然后解释你想做什么。(XY 问题) - dtech
显示剩余8条评论
2个回答

4
Parsing C(即使仅限于“头文件”)很难;语言比人们记得的更加复杂,还有预处理器,最后是解析内容的问题。C++基本上包括了所有的C内容,而C++11则让问题变得更加严重。
通常人们可以使用Perl或其他字符串技巧中的正则表达式,针对有限的输入集合编写出98%的解决方案。如果这对您有效,那么就好。但通常情况下,剩下的2%会导致被篡改的解析器死机或产生错误答案,然后您就需要调试结果并手动修改98%的输出解决方案。
黑客式的解决方案在真实的头文件中往往会失败得非常惨,因为这些文件似乎会将怪异之处集中在宏和条件语句中(有时甚至混合使用不同的C和C++方言)。以典型的Microsoft .h文件为例。这似乎是OP想要处理的内容。预处理可以解决部分问题,现在你需要面对真正复杂的C和/或C++。即使进行了预处理,你也无法得到真实头文件的98%解决方案;你还需要typedefs,因此需要名称和类型解析。你可能会“解析”FOO X; 这告诉你X是FOO类型……哎呀,那是什么?只有符号表才知道确切信息。

GCCXML完成所有这些预处理、解析和符号表构建……针对的是GCC的C方言。微软的方言不同,我认为GCCXML无法处理它。

一个更通用的工具是我们的DMS软件重构工具包,它有C前端;还有一个C++前端(是的,它们不同;C和C++远非同一种语言)。这些处理各种C方言(在正确配置时包括MS和GCC),进行宏/条件展开,构建AST和符号表(正确地执行名称和类型解析等操作)。
您可以添加自定义内容以提取所需信息,通过遍历生成的符号表结构。由于DMS未使用.net语言实现,因此您将不得不将所需内容导出到C#中(例如生成您的C#类)。

0
在最一般的情况下,头文件只能被使用,而不能被转换。
这是因为预处理器(#define)可以使用宏、结构常量等片段,只有在上下文中使用时才具有意义。
例如:
  • 任何带有##的宏
或者
//header
#define mystructconstant "bla","bla"

// in using .c
char test[10][2] ={mystructconstant};

但是你不能简单地丢弃所有宏,因为那样你就无法处理非常常见的调用约定宏。

等等等等。

因此,头文件解析和转换大多只适用于半自动化使用(手动运行经过清理的头文件)或相对干净和一致的头文件(例如旧的MS SDK头文件)。

由于一般情况非常困难,因此没有太多现成的工具可用。每个人都会为自己的头文件制作一些快速而肮脏的东西。

我知道的唯一更通用的工具是SWIG。


我正在使用MSVC的cl.exe,并带有/EP标志来生成经过预处理后的头文件版本。这种方法真正简化了数据解析。我还发现了gcc-xml,它可以为头文件编译生成XML输出。但我有一种感觉,肯定有更好的方法... - drzoidberg
我不会期望基于GCC的GCCXML解析MS头文件,因为Microsoft使用了不同的黑暗语法角落。 - Ira Baxter
预处理使得编程更加容易,但结果通常是不完整的(就像上面的“mystructconstant将会消失”)。预处理可以修复头文件中的替换,但不能修复实现中的替换。 - Marco van de Voort

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