从C源代码中自动删除未使用的局部变量

时间:2009-02-18 12:43:57

标签: c automated-refactoring

我想从C文件中删除未使用的局部变量。 例如:

int fun(int a , int b)
{
  int c,sum=0;
  sum=a + b;
    return sum;
}

这里未使用的变量是'c'。

我将在外部列出所有未使用的局部变量。现在使用我所拥有的未使用的局部变量,我们必须从源代码和放大器中找到局部变量。删除。
在上面的例子中,“c”是未使用的变量。我会知道它(我有代码)。 在这里,我必须找到c&删除它。

修改

关键是不要使用外部工具查找未使用的局部变量。关键是要从列表中删除它们。

10 个答案:

答案 0 :(得分:21)

调高编译器警告级别,它应该告诉你。

将源片段放在“f.c”中:

% gcc -c -Wall f.c
f.c: In function 'fun':
f.c:1: warning: unused variable 'c'

答案 1 :(得分:10)

整蛊 - 你必须为此解析C代码。结果有多接近? 我的意思是:

int a, /* foo */
    b, /* << the unused one */
    c; /* bar */

现在,人们很明显第二条评论必须要去。

轻微变化:

void test(/* in */ int a, /* unused */ int b, /* out */ int* c);

同样,第二条评论必须去,这次是b之前的评论。

通常,您希望解析输入,过滤它,并发出不是未使用变量声明的所有内容。您的解析器必须保留注释和#include语句,但如果您没有#include标头,则可能无法识别声明(如果使用宏来隐藏声明,则更是如此)。毕竟,你需要标题来决定是否A * B();是函数声明(当A是类型时)或乘法(当A是变量时)


[edit]此外:

即使您知道变量未使用,删除它的正确方法也很大程度上取决于远程上下文。例如,假设

int foo(int a, int b, int c) { return a + b; }

显然,c未被使用。你能把它改成吗?

int foo(int a, int b) { return a + b; }

也许,但不是如果&amp; foo存储在int(*)(int,int,int)中。这可能发生在其他地方。如果(且仅当)发生这种情况,您应该将其更改为

int foo(int a, int b, int /*unused*/ ) { return a + b; }

答案 2 :(得分:5)

你为什么要这样做?假设您有一个不错的优化编译器(GCC,Visual Studio等),二进制输出将与您删除原始示例中的'int c'不同。

如果这只是代码清理,任何最新的IDE都会为您提供每个警告的源代码的快速链接,只需单击并删除:)

答案 3 :(得分:5)

我的回答更多是对MSalters非常彻底的回答的精心评论。 我会超越'棘手',并说这样的工具既不可能也不可取。

如果您只想删除对变量的引用,那么您可以编写自己的代码解析器,但是需要区分它所在的函数上下文,例如

int foo(double a, double b)
{
   b = 10.0;
   return (int) b;
}

int bar(double a, double b)
{
   a = 5.00;
   return (int) a;
}

任何简单的解析器都会遇到麻烦,'a'和'b'都是未使用的变量。

其次,如果您将评论视为MSalter,您会发现人们不会持续评论;

double a;
/*a is designed as a dummy variable*/
double b;

/*a is designed as a dummy variable*/
double a;
double b;

double a; /*a is designed as a dummy variable*/
double b;

等。

因此,简单地删除未使用的变量将创建孤立的评论,这可能比not commenting at all更危险。

最终,优雅地执行是一项非常困难的任务,无论如何你都会破坏代码。通过自动化流程,您可能会使代码变得更糟。

最后,您应该首先考虑变量在代码中的原因,如果它们被弃用,为什么在所有引用都没有删除它们时。

答案 4 :(得分:1)

保罗正确地说明了警告级别之外的

Static code analysis tools

答案 5 :(得分:1)

除了能够通过警告显示这些内容之外,如果打开任何优化,编译器通常会优化这些。检查变量是否从未被引用在编译器中的实现方面是非常简单的。

答案 6 :(得分:0)

你需要一个好的解析器来保留令牌的原始角色位置(即使存在预处理器!)。有一些自动重构C / C ++的工具,但它们远非主流。

我建议你查看Taras' Blog。这家伙正在做一些Mozilla代码库的大型自动重构,比如用返回值替换out-params。他重写代码的主要工具是Pork

  

Pork是一个C ++解析和重写   工具链。 Pork的核心是C ++   提供精确字符的解析器   开始和结束的位置   每个AST节点,以及一组   包含any的宏扩展   地点。这个信息允许C ++   要自动重写   精确的方式。

来自博客:

  

到目前为止猪肉已被用于“未成年人”   比如重命名   课程和功能,旋转   outparameters和纠正prbool   错误。此外,Pork证明了自己   在涉及的实验中   重写几乎所有功能(即   在Mozilla中生成3 + MB补丁   使用垃圾收集代替   引用计数。

适用于C ++,但它可能适合您的需求。

答案 7 :(得分:0)

上面的一张海报上写着“不可能和不可取”。 另一个说“棘手”,这是正确的答案。 你需要1)一个完整的C(或任何感兴趣的语言)解析器, 2)理解语言的推理程序 标识符引用和数据流以确定变量 确实是“死”,3)实际修改的能力 源代码。

所有这些都很难建立的巨大能量 1)2)3)。您不能为任何单独的清理任务辩护。 人们可以做的是专门建立这样的基础设施 目标是在很多不同的方面分摊它 程序分析和转换任务。

我公司提供这样的工具:DMS软件再造 工具包。看到 http://www.semdesigns.com/Products/DMS/DMSToolkit.html DMS具有多种语言的生产质量前端, 包括C,C ++,Java和COBOL。

事实上,我们已经建立了一个自动化的“查找无用的声明” Java工具做两件事: a)将它们全部列出(从而生成列表!) b)使用无用的声明制作代码的副本    除去。 您可以选择要保留的答案: - )

为C做同样的事情并不困难。我们已经 有一个工具可以识别这些死变量/函数。

我们没有加入的一个案例是“无用的参数” case,因为删除了一个无用的参数,你有 找到来自其他模块的所有调用, 验证设置参数没有侧面 效果,并撕掉无用的论点。 事实上,我们有完整的软件图表 感兴趣的系统,所以这也是 可能的。

所以,它只是棘手,甚至不是很棘手 如果你有合适的基础设施。

答案 8 :(得分:-1)

另外:splint

  

Splint是一种用于静态检查C程序是否存在安全漏洞和编码错误的工具。只需很少的努力,Splint可以用作更好的棉绒。如果投入额外的工作为程序添加注释,Splint可以执行比任何标准lint更强的检查。

答案 9 :(得分:-1)

您可以将问题解决为文本处理问题。必须有少量的正则表达式模式,如何在源代码中定义未使用的局部变量。

使用未使用的变量名称列表及其所在的行号,您可以逐行处理C源代码。在每一行上您可以迭代变量名称。在每个变量名称上您可以逐个匹配模式。成功匹配后您知道定义的语法,因此您知道如何从中删除未使用的变量。

例如,如果源行是:“int a,unused,b;”并且编译器将“未使用”报告为该行中未使用的变量,而模式“/,unused,/”将匹配,您可以用单个“,”替换该子字符串。