10

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

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

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

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

编辑

关键是不要使用外部工具找到未使用的局部变量。关键是从代码中删除它们,给出它们的列表。

4

10 回答 10

21

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

将您的源代码片段放入“fc”:

% gcc -c -Wall f.c
f.c: In function 'fun':
f.c:1: warning: unused variable 'c'
于 2009-02-18T12:46:37.980 回答
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 是变量时)


[编辑] 此外:

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

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

显然,c 未被使用。可以改成吗?

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

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

int foo(int a, int b, int /*unused*/ ) { return a + b; }
于 2009-02-18T12:53:56.217 回答
5

你为什么要这样做?假设您有一个不错的优化编译器(GCC、Visual Studio 等),无论您是否删除原始示例中的“int c”,二进制输出都不会有任何不同。

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

于 2009-02-18T14:02:32.713 回答
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;

等等

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

归根结底,优雅地完成这是一项非常困难的任务,无论如何你都会修改代码。通过自动化这个过程,你会让代码变得更糟。

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

于 2009-02-18T15:17:37.073 回答
1

Paul 正确指出的警告级别之外的静态代码分析工具

于 2009-02-18T12:48:37.913 回答
1

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

于 2009-02-18T12:48:52.593 回答
0

您将需要一个好的解析器来保留标记的原始字符位置(即使存在预处理器!)。有一些用于 C/C++ 自动重构的工具,但它们远非主流。

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

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

来自博客:

到目前为止,猪肉已被用于“次要”事情,例如重命名类和函数、旋转超参数和纠正 prbool 错误。此外,Pork 在一项实验中证明了自己,该实验涉及重写 Mozilla 中的几乎所有函数(即生成 3+MB 补丁)以使用垃圾收集而不是引用计数。

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

于 2009-02-24T08:10:13.560 回答
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 做同样的事情并不难。我们已经有一个工具可以识别这些死变量/函数。

一个我们没有提到的情况,是“无用参数”的情况,因为要删除一个无用的参数,你必须找到所有来自其他模块的调用,验证设置参数没有副作用,然后撕掉无用的论点。事实上,我们有整个感兴趣的软件系统的完整图表,所以这也是可能的。

所以,这很棘手,如果你有正确的基础设施,甚至不是很棘手。

于 2009-06-14T06:03:09.533 回答
-1

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

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

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

于 2009-09-18T13:39:45.677 回答
-1

另外:夹板

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

于 2009-02-18T12:48:30.957 回答