我正在寻找一种在项目的C / C ++代码中搜索给定术语的方法,同时忽略注释和字符串中的任何内容。
由于代码库很大,我正在寻找一种方法来自动识别与我的搜索词匹配的代码行,因为它们需要人工检查。
如果可能的话,我想在Linux系统上执行搜索。
背景
所讨论的代码库是带有大量第三方插件的实时信号处理引擎。插件以多种语言实现(大多数语言是C,但也包括C ++和其他语言;目前我只关心这两种语言),尚未执行任何标准。
我们的代码库当前将内置类型float用于浮点数,我们希望将其替换为允许使用双精度数的typedef。
我们想在实际代码中查找所有出现的float(忽略注释和打印输出中的合法使用)。
使事情变得更复杂的是,代码有效载荷中有一些(尽管很少)float的合法使用(因此,我们真正在寻找一种方法来标识所有需要手动检查的位置,而不是运行一些自动搜索和-更换。)
该代码还包含对(float)的C样式静态强制转换,因此通常不能选择依靠编译器警告来标识类型不匹配。
该代码库由3000多个(C和C ++)文件组成,累积了大约75万行代码。
该代码是跨平台的(linux,osx,w32是主要目标;还有freebsd和类似的东西),并使用各种本机编译器(gcc / g ++,clang / clang ++,VisualStudio等)进行了编译。
至今…
到目前为止,我正在使用类似丑陋的东西:
grep”\bfloat\b” | sed -e ‘s|//.*||’ -e ‘s|”[^”]*”||g’ | grep”\bfloat\b”
但我认为必须有一些更好的方法来仅搜索有效载荷代码。
您的代码在做什么?它的大小是多少?什么编译器和平台?请修改您的问题以进行改进。
根据您代码库的大小,我可能只是使用emacs手动进行处理。否则,我可能只是替换所有它们,并在以后修复虚假注释。我很懒。 🙂
BTW C / C ++不存在。给定的翻译单元编码为C ++(然后至少选择C ++ 11标准)或C(如果可能,请选择C11,或者至少选择C99)。
@BasileStarynkevitch虽然我不明白为什么要了解用于编译我的C和C ++文件的编译器的原因,但我已经添加了该信息。我完全不知道为什么C标准(或C ++标准)应该具有任何意义。
因为如果使用GCC,则可以使用MELT对其进行自定义(但是,如果使用其他编译器,则不能使用MELT)。另外,我的观点是,没有C / C ++这样的语言。最后,如果要在2016年使用C ++进行编码,我强烈建议至少为C ++ 11编码(这是一种与其前代产品截然不同的语言)
@BasileStarynkevitch更新了问题,希望可以回答这些问题;希望我也可以阐明” C / C ++”的含义
我的感觉是,MELT绝对值得您使用。但是作为MELT的作者,我有偏见。
取决于您的编辑器/ IDE。 GCC和VIM支持” ctags”,几个Linux IDE也一样。在VIM中,可以使用ctrl-]或g ctrl-]转到光标下方的符号。 vim.wikia.com/wiki/Browsing_programs_with_tags
另外,几个IDE都具有执行此操作的功能,例如Visual Studio重构>重命名。我个人使用了Whole Tomatos Visual AssistX,而我在更大的代码库上做了多次这样的事情。
恕我直言,” Unix&Linux”上有一个类似问题的很好答案:
grep works on pure text and does not know anything about the
underlying syntax of your C program. Therefore, in order not search
inside comments you have several options:
Strip C-comments before the search, you can do this using gcc
-fpreprocessed -dD -E yourfile.c For details, please see Remove comments from C/C++ code
Write/use some hacky half-working scripts like you have already found
(e.g. they work by skipping lines starting with // or /*) in order to
handle the details of all possible C/C++ comments (again, see the
previous link for some scary testcases). Then you still may have false
positives, but you do not have to preprocess anything.
Use more advanced tools for doing”semantic search” in the code. I
have found”coccigrep”: http://home.regit.org/software/coccigrep/ This
kind of tools allows search for some specific language statements
(i.e. an update of a structure with given name) and certainly they
drop the comments.
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类型的所有匹配项-但仅将其中大多数替换为-x …,因为(或标准)功能需要float。
CADNA工具也可能有用,可以帮助您估计结果的准确性(因此,帮助您确定何时使用double是明智的)。
使用诸如GCC MELT,CADNA,Coccinelle,Frama-C(或g0hl1n的答案中提到的F??luctuat或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=’: ‘ ‘/\/{print file, $0}’
done
第一个sed用唯一的标识符字符串替换所有哈希(#)和__符号,以便预处理器不对#include等进行任何扩展,但是我们可以在预处理后恢复它们。
gcc预处理输入以去除注释。
第二个sed用实际的哈希符号替换我们先前添加的哈希标识符字符串。
awk实际上在单词边界内搜索float,如果找到,则会打印文件名及其所在的行。这对字边界\使用GNU awk。
第二个sed的工作可以作为awk命令的一部分来完成,但是我喜欢第二个sed的对称性。
与您使用cscope不同,此sed / gcc / sed / awk方法不会避免在字符串中找到错误的匹配项,但希望这些匹配项很少,您可以在手动进行后期处理的同时将其淘汰。
对于包含换行符的文件名,它将不起作用-如果可以的话,请在脚本中使用正文并将其作为find .. -print0 | xargs -0 script执行。
通过添加您正在使用的任何C或C ++版本来修改gcc命令行,例如-ansi。