使用 sed 或 awk 预处理 C/C++ 代码时如何定位可靠的函数?

Posted

技术标签:

【中文标题】使用 sed 或 awk 预处理 C/C++ 代码时如何定位可靠的函数?【英文标题】:how to target reliably functions when pre-processing C/C++ code with sed or awk? 【发布时间】:2014-12-31 04:03:58 【问题描述】:

我想通过使用 sed/awk 预处理源文件来直接检测我的代码。我不能使用其他方法,如调试器跟踪或 gcc 选项-finstrument-functions。在最后一种情况下,地址以某种我无法管理的方式重新定位,并且我错过了与符号表的对应关系。 here(ptrace、etrace、callgraph 等)或 here 提供的其他方法在一个简单的示例中效果很好,但在我的实际项目中却不行。

问题是在处理大型开源项目时,函数的编写标准不同,不仅在 C 和 C++ 文件之间,而且经常在同一个文件中。 可能在参数列表的末尾,或者在另一行,结构或赋值可能使用起始 ,使得简单的函数解析错误。

因此上述链接中在函数定义开头插入宏的解决方案通常不起作用,并且手动更正代码行数(KLOC)是不可行的。

sed 's/^/ENTRY/'

那么,如何在 C/C++ 代码中使用可用于 sed 或 awk 的正则表达式来定位可靠的函数定义?可能通过使用 gcc 预编译器代码的一部分?我正在寻找可能是现成的东西。

【问题讨论】:

【参考方案1】:

sedawk(或任何纯文本方法)是处理可靠 C 代码的错误工具(您可能应该使用预处理的表单)。

您想处理某种形式的编译器AST。当然,编译器内部的表示是特定于编译器的(甚至可能是它的版本)。

如果使用最近的 GCC,您可以使用 MELT(并将您的通行证添加到 GCC)或使用您自己的 C++ 插件对其进行自定义。

如果使用Clang/LLVM,您还可以通过添加您的通行证来自定义它。

Coccinelle 工具也可能是相关的。

任何此类方法都需要大量工作(可能需要数周时间),因为您需要详细了解您正在使用的特定编译器的内部表示。而 C 语言的复杂程度足以让这一点变得不平凡。

【讨论】:

LibClang 和 Python 绑定也可能是一个选项作为预处理器 - 使用 Clang 的解析功能,根据需要修改 AST,然后再次输出与修改后的 AST 对应的 C++ 源,最后运行此源文件上的正常 Clang。 MELT 看起来很棒并且是***解决方案,但学习曲线对于我的迫切需要来说太高了。 所有方法都要求您了解编译器的内部结构(及其 AST)。这是主要的困难。因此是“数周的努力”。【参考方案2】:

您不能使用任何不理解您的代码所使用的特定 C 版本(例如 C++ 或 ANSI-C 或 C-99)的工具来执行此操作。举个简单的例子——“//”在“C 函数”中是什么意思?好吧,如果它在字符串内部,它是一对文字斜线,如果它在字符串外部,如果代码是 C++ 或 C-99,它可能是注释的开始,但它不是 ANSI-C 中注释的开始。如果它在/* ... // ... */ 里面呢?如果“//”后面看起来像函数定义,那真的是函数吗?

你没有说你想做什么(“预处理代码”并没有告诉我们任何事情),但你应该考虑使用我在Remove multi-line comments 上发布的内容来使用 gcc 剥离代码cmets 和 C 美化器(如“indent”或“cb”)一致地重新格式化代码和/或查看“cscope”或“ccalls”,如果您只是在寻找列出函数的工具。

【讨论】:

在我的帖子的开头,我用 -finstrument-functions 和其他方法讨论了带有链接的痕迹。这意味着我想在代码中添加有用的信息跟踪,而不是剥离它。 对我来说不是这个意思。我不知道-finstrument-functions 是什么意思,也不知道您为什么要谈论调试器跟踪。您是说要在输入/退出函数或其他内容时将打印语句添加到代码中吗?如果是这样,您希望这些打印语句输出什么?您错过了我的帖子的重点-我不是在告诉您如何剥离代码,而是在告诉您如何以一致的方式重新格式化它,以便您可以编写/使用工具来查找函数开始,等等

以上是关于使用 sed 或 awk 预处理 C/C++ 代码时如何定位可靠的函数?的主要内容,如果未能解决你的问题,请参考以下文章

sed-awk的简单操作

正则表达式 - grep、sed、awk - 处理大型文本文件

Linux sed和awk

课时13:sed和awk使用方法

将月份名称更改为sed awk或批处理中特定行的月份编号

sed使用