如何在C++中找到一个函数的所有调用者?

17

我正在重构一些C++代码,想要弃用一些旧的方法。我目前查找所有方法的方法如下:

  1. 在我的工作源文件中注释掉原始方法。
  2. 尝试编译代码。
  3. 如果出现编译器错误,则进行注释并尝试重新编译。
  4. 一旦编译成功完成,我就找到了所有的调用。

这太糟糕了。我也尝试过在源代码中搜索函数调用的名称,但有时会遇到同名但参数不同的函数问题,因此我的编译器需要帮我解析名称。我在这个问题中找到了一些C#的解决方案,但我的代码库完全是用C++实现的。

有没有更好的方法来查找C++中类方法或函数的所有调用者?我正在Unix系统上使用GCC,但跨平台的解决方案将是最佳的选择。


我很想听到一个好的解决方案,但在我看来,你似乎必须复制整个前端。这几乎是构建符号表所需的全部。 - David Thornley
1
尝试使用 CodeQuery。它结合了 cscope 和 ctags 的优点,以产生更好的 C++ 源代码信息。声明:这是我的开源项目。 - ruben2020
9个回答

36

GCC允许您使用__attribute__((deprecated))修饰变量、函数和方法,这会在所有调用点产生警告(除非使用-Wno-deprecated-declarations)。

class A {
public:
    A() __attribute__((deprecated)) {}
};
int main() {
    A a;
}
$ g++ test.c
test.cc: 在函数 ‘int main()’ 中:
test.cc:6: 警告:‘A::A()’已经被弃用(在 test.cc:3 中声明)

1
很好。既然OQ使用GCC(没有提到其他平台),那么这就是我会做的。 - T.E.D.
9
对于使用Visual Studio的人来说,可以使用#pragma deprecated(functionname)实现类似的功能。详见http://msdn.microsoft.com/en-us/library/044swk7y.aspx。 - Eclipse
这对我来说是正确的答案,因为我正在重构,我不需要属性跨平台。很好! - James Thompson
5
GCC的属性语法中有一个好处,就是在使用时需要使用双括号。这使得我们可以很容易地在其他编译器中使用#ifndef __GNUC__ #define __attribute__(x) /* nothing */ #endif来替代这些属性。请注意,这不会改变原意。 - ephemient

10

Eclipse无需任何插件即可完成此操作。即使您不想将其用作日常编辑器,它也可以成为这类任务的有用工具。

  1. 下载、安装并运行Eclipse CDT
  2. 在“文件”菜单下选择“新建C++项目”。输入项目名称,从“项目类型”树视图中选择“空Makefile项目”,取消“使用默认位置”的选项并输入项目所在的文件夹。
  3. 单击“下一步”,然后单击“完成”。
  4. Eclipse将自动开始索引您的项目。如果它确实是一个Makefile项目,并且由于您正在使用g ++,您可以从Eclipse内部进行完全清除,然后进行构建(在“项目”菜单下),它应该会自动使用您现有的makefile,并自动发现您的包含目录和其他项目设置。
  5. 在源文件中找到重载函数的原型,右键单击它,选择“引用”,然后选择“项目”。Eclipse将在您的项目内查找所有对该函数的引用,仅针对特定重载版本。

您还可以使用Eclipse内置的重构支持重命名重载函数,以便它们不再被重载。Eclipse也完全跨平台;您甚至可以将其索引器、搜索引用和重构功能用于在其他IDE中维护和构建的项目。


1
模拟回答!我听从您更完整的答案,并奖励您一个赞 :-) - David Citron

6
一种选择是通过像Cscope这样的程序运行整个项目。它基本上解析整个项目的源代码并构建一个数据库,允许轻松搜索诸如所有函数调用者、所有引用等内容。
我知道它在C方面工作得相当好,并且他们声称它对C++也有不错的效果。KScope是其KDE GUI前端。

2
糟糕,我一直很有希望,直到看到你的“他们声称它对C++运行良好”。根据你的帖子,我以为你是从第一手经验中说出来的。我非常喜欢用cscope处理C代码,即使是大型、复杂的C代码,但在处理C++代码时,我的结果却参差不齐。我想我应该试着修复cscope,毕竟它在Sourceforge上... - Dan

4

我认为您想要查看调用图。请参考这个问题,了解如何进行调用图的可视化。


谢谢提供链接!我在搜索中没有看到那个问题。 - James Thompson

4

如果有人想在Windows下使用Visual Studio来完成此操作...

Visual Assist非常好用。它在许多C++重构、调用图、重命名、自动生成标头定义或从定义生成方法等方面都有很大帮助。虽然不完美,但相对于Java/C#重构工具的质量,它在C++中表现得非常出色!


3
这款Eclipse插件可能是合适的工具:CallGraph View。您可以访问此链接了解更多详情。

2

这就是我通常的做法。如果你的代码都在一个地方,使用“grep”(或者“find | grep”组合)可能也能达到效果。

但是需要注意:这种方法很容易错过那些没有编译进当前配置的实例。如果你的代码使用了#ifdef来支持多个配置,一位认真负责的人会尝试用每个配置进行编译,以便捕捉到所有实例。


这是一个非常好的观点。幸运的是,我们的代码中没有太多的#ifdef,而且我不指望在这个特定的重构项目中会有太多的#ifdef,但这也是我需要更好的技巧的另一个原因。 :) - James Thompson

2
如果您让Eclipse CDT索引您的源代码库,那么您应该能够查看任何函数的调用层次结构,甚至执行一些重构操作。
您可以下载适用于C/C++开发人员的Eclipse IDE(希望您能找到适合您特定*NIX的版本),并按照他们的说明进行操作。

2

在Visual Studio中,右键单击函数名称并点击“调用浏览器”>“显示调用者图”。

然后,在显示窗口中应该有一个名为“Calls to function”的文件夹,其中包含所有调用该函数的位置,您可以双击它们以在代码中查看它们。


在较新的VS版本中,上下文菜单项被命名为“调用层次结构”。 - Justin R.
在VS 2013中,似乎是查看调用层次结构。 - Watusimoto

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