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

how to find a search term in source code

本文关键字:查找 搜索 源代码      更新时间:2023-10-16

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

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

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

背景

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

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

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

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

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

代码是跨平台的(Linux,OSX,W32是主要目标;还有FreeBSD和类似),并使用各种本机编译器(gcc/g ++,clan/clang++,VisualStudio,...)编译。

迄今。。。

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

 grep "bfloatb" | sed -e 's|//.*||' -e 's|"[^"]*"||g' | grep "bfloatb"

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

恕我直言,在"Unix和Linux"中有一个类似的问题有一个很好的答案:

grep 在纯文本上工作,对 C 程序的基础语法。因此,为了不搜索 在评论中,您有以下几种选择:

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

  2. 编写/使用一些像你已经发现的笨拙的半工作脚本 (例如,它们通过跳过以//或/* 开头的行来工作,以便 处理所有可能的 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(可能适合typedef -ed...)替换 float 类型的所有出现 - 但只替换其中的大部分 - 因为很可能您正在使用一些需要float的外部(或标准)函数。

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

使用语义工具,如GCC MELT,CADNA,Coccinelle,Frama-C(或者可能是Fluctuat,或g0hl1n的答案中提到的Coccigrep)将给出更精确或相关的结果,代价是不得不花费更多时间(也许是几天!)来学习和定制工具。

执行此操作的可靠方法应该是使用 find this C symbol 选项在面向行的模式下使用 cscope (http://cscope.sourceforge.net/),但我还没有在各种 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=': ' '/<float>/{print file, $0}'
done

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

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

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

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

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

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

它不适用于包含换行符的文件名 - 如果您有换行符,您可以将正文放入脚本中并按find .. -print0 | xargs -0 script执行。

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