如何在源代码中查找搜索词

我正在寻找一种方法来搜索项目的C / C ++代码中的给定术语,同时忽略注释和字符串中的任何出现。

由于代码库相当大,我正在寻找一种方法来自动识别与我的搜索词匹配的代码行,因为它们需要手动检查。

如果可能的话,我想在我的linux系统上执行搜索。

背景

有问题的代码库是一个带有大量第三方插件的实时信号处理引擎。 插件是用各种语言实现的(主要是C语言,还有C ++和其他语言;目前我只关心这两种语言),没有强制执行任何标准。

我们的代码库目前使用内置类型float来表示浮点数,我们想用一个允许我们使用双精度数的typedef替换它。 我们希望在实际代码中找到所有出现的float (忽略注释和打印输出中的合法用法)。

更复杂的是,在代码有效负载中有一些(虽然很少) 合法使用float (因此我们真的在寻找一种方法来识别所有需要手动检查的地方,而不是运行一些自动搜索和替换。)

代码还包含C样式的静态强制转换为(float) ,因此依靠编译器警告来识别类型不匹配通常不是一种选择。

代码库由超过3000个(C和C ++)文件组成,累积约750000行代码。

代码是跨平台的(linux,osx,w32是主要目标;但也是freebsd和类似的),并使用各种本机编译器(gcc / g ++,clang / clang ++,VisualStudio,…)进行编译。

至今…

到目前为止,我正在使用丑陋的东西:

  grep "\bfloat\b" | sed -e 's|//.*||' -e 's|"[^"]*"||g' | grep "\bfloat\b" 

但我认为必须有一些更好的方法来搜索有效载荷代码。

恕我直言,在“Unix&Linux”上有类似问题的答案很好:

grep适用于纯文本,并且对C程序的基础语法一无所知。 因此,为了不在内部评论中搜索,您有以下几种选择:

  1. 在搜索之前删除 C-comments,您可以使用gcc -fpreprocessed -dD -E yourfile.c来执行此操作。有关详细信息,请参阅从C / C ++代码中删除注释

  2. 编写/使用一些你已经找到的hacky半工作脚本(例如,它们通过跳过以//或/ *开头的行来工作),以便处理所有可能的C / C ++注释的细节(同样,请参阅上一个链接一些可怕的测试用例)。 然后你仍然可能有误报,但你不必预处理任何东西。

  3. 使用更高级的工具在代码中进行“语义搜索”。 我找到了“coccigrep”: http ://home.regit.org/software/coccigrep/这种工具允许搜索某些特定的语言语句(即更新具有给定名称的结构),当然他们会删除评论。

https://unix.stackexchange.com/a/33136/158220

虽然它并没有完全涵盖你的“不在字符串”的要求。

它实际上可能取决于代码库的大小,也可能取决于您通常使用的编辑器。 我建议使用GNU emacs (如果可能的话,在Linux上使用最近的GCC编译器……)

对于小到中等大小的代码(例如小于300KLOC),我建议使用Emacs的grep模式 。 然后(假设您已将next-error Emacs函数绑定到某个键,可能在~/.emacs使用(global-set-key [f10] 'next-error) ),您可以快速扫描每次出现的float (甚至在字符串或注释中,但你会很快跳过这样的事件……)。 几个小时后,您将完成中等大小的源代码(这比学习如何使用新工具更快)。

对于大型代码(数百万行),定制一些静态分析工具或编译器可能是值得的。 您可以使用GCC MELT在Linux上自定义GCC编译器。 它的findgimple模式可能是鼓舞人心的,甚至可能很有用(你可能想找到所有针对float Gimple分配)

顺便说一句,您可能不希望用double替换所有出现的 – 但只有大多数 – float类型(可能是适当的typedef -ed …),因为很可能你正在使用一些外部(或标准)函数需要一个float

CADNA工具也可能有用,可帮助您估计结果的精确度(因此,帮助您决定何时使用double是明智的)。

使用GCC MELT , CADNA , Coccinelle , Frama-C等语义工具(或者在g0hl1n的答案中提到的Fluctuat或Coccigrep )可以给出更精确或相关的结果,代价是花费更多的时间(可能是几天!)来学习并自定义该工具。

执行此操作的强大方法应该是使用cscopehttp://cscope.sourceforge.net/ )在面向行的模式下使用find this C symbol选项,但我没有在各种C标准上使用它,所以如果这样做不适合你或如果你不能得到cscope然后这样做:

 find . -type f -print | while IFS= read -r file do sed 's/a/aA/g;s/__/aB/g;s/#/aC/g' "$file" | gcc -P -E - | sed 's/aC/#/g;s/aB/__/g;s/aA/a/g' | awk -v file="$file" -v OFS=': ' '/\/{print file, $0}' done 

第一个sed用唯一标识符字符串替换所有哈希( # )和__符号,这样预处理器不会对#include等进行任何扩展,但我们可以在预处理后恢复它们。

gcc预处理输入以去除注释。

第二个sed将我们之前添加的哈希标识符字符串替换为实际的哈希符号。

awk实际上在单词边界内搜索float ,如果找到则打印文件名加上它找到的行。 这使用GNU awk进行字边界\<\>

第二个sed的工作可以作为awk命令的一部分完成,但我喜欢2个seds的对称性。

与使用cscope不同,这种sed / gcc / sed / awk方法不会避免在字符串中找到错误的匹配,但希望其中很少有这些,你可以在手动后处理时将它们清除掉。

它不适用于包含换行符的文件名 - 如果你有那些你可以但脚本中的正文并将其作为find .. -print0 | xargs -0 script执行find .. -print0 | xargs -0 script find .. -print0 | xargs -0 script

通过添加您正在使用的任何C或C ++版本来修改gcc命令行,例如-ansi