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

发布于 2024-07-14 07:54:47 字数 381 浏览 13 评论 0原文

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

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

此处未使用的变量是“c”。

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

编辑

重点不是使用外部工具查找未使用的局部变量。 重点是从给定它们列表的代码中删除它们。

I want to delete unused local variables from C file.
Example:

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

Here the unused variable is 'c'.

I will externally have a list of all unused local variables. Now using unused local variables which I have, we have to find local variables from source code & delete.
In above Example "c" is unused variable. I will be knowing it (I have code for that).
Here I have to find c & delete it .

EDIT

The point is not to find unused local variables with an external tool. The point is to remove them from code given a list of them.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(10

谢绝鈎搭 2024-07-21 07:54:47

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

将源片段放入“fc”中:

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

Turn up your compiler warning level, and it should tell you.

Putting your source fragment in "f.c":

% gcc -c -Wall f.c
f.c: In function 'fun':
f.c:1: warning: unused variable 'c'
全部不再 2024-07-21 07:54:47

棘手 - 您必须为此解析 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(*)(int,int,int) 中则不然。 这可能会发生在其他地方。 如果(且仅当)发生这种情况,您应该将其更改为

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

Tricky - you will have to parse C code for this. How close does the result have to be?
Example of what I mean:

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

Now, it's obvious to humans that the second comment has to go.

Slight variation:

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

Again, the second comment has to go, the one before b this time.

In general, you want to parse your input, filter it, and emit everything that's not the declaration of an unused variable. Your parser would have to preserve comments and #include statements, but if you don't #include headers it may be impossible to recognize declarations (even more so if macro's are used to hide the declaration). After all, you need headers to decide if A * B(); is a function declaration (when A is a type) or a multiplication (when A is a variable)


[edit] Furthermore:

Even if you know that a variable is unused, the proper way to remove it depends a lot on remote context. For instance, assume

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

Clearly, c is unused. Can you change it to ?

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

Perhaps, but not if &foo is stored int a int(*)(int,int,int). And that may happen somewhere else. If (and only if) that happens, you should change it to

int foo(int a, int b, int /*unused*/ ) { return a + b; }
北城孤痞 2024-07-21 07:54:47

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

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

Why do you want to do this? Assuming you have a decent optimizing compiler (GCC, Visual Studio et al) the binary output will not be any different wheter you remove the 'int c' in your original example or not.

If this is just about code cleanup, any recent IDE will give you quick links to the source code for each warning, just click and delete :)

失与倦" 2024-07-21 07:54:47

我的回答更多的是对 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;

因此

,简单地删除未使用的变量将创建孤立的注释,这可以说比 不更危险根本不发表评论

最终,优雅地完成这是一项极其困难的任务,而且无论如何你都会破坏代码。 通过自动化该过程,您将使代码变得更糟。

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

My answer is more of an elaborate comment to MSalters' very thorough answer.
I would go beyond 'tricky' and say that such a tool is both impossible and inadvisable.

If you are looking to simply remove the references to the variable, then you could write a code parser of your own, but it would need to distinguish between the function context it is in such as

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

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

Any simple parser would have trouble with both 'a' and 'b' being unused variables.

Secondly, if you consider comments as MSalter has, you'll discover that people do not comment consistently;

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;

etc.

So simply removing the unused variables will create orphaned comments, which are arguably more dangerous than not commenting at all.

Ultimately, it is an obscenely difficult task to do elegantly, and you would be mangling code regardless. By automating the process, you would be making the code worse.

Lastly, you should be considering why the variables were in the code in the first place, and if they are deprecated, why they were not deleted when all their references were.

悲念泪 2024-07-21 07:54:47

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

Static code analysis tools in additional to warning level as Paul correctly stated.

若水微香 2024-07-21 07:54:47

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

As well as being able to reveal these through warnings, the compiler will normally optimise these away if any optimisations are turned on. Checking if a variable is never referenced is quite trivial in terms of implementation in the compiler.

念﹏祤嫣 2024-07-21 07:54:47

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

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

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

来自博客:

到目前为止,猪肉已被用于“未成年人”
诸如重命名之类的事情
类和函数,轮换
输出参数和校正 prbool
错误。 此外,猪肉证明了自己
在一项涉及的实验中
重写几乎每个函数(即
在 Mozilla 中生成 3+MB 补丁)
使用垃圾收集代替
引用计数。

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

You will need a good parser that preserves original character position of tokens (even in presence of preprocessor!). There are some tools for automated refactoring of C/C++, but they are far from mainstream.

I recommend you to check out Taras' Blog. The guy is doing some large automated refactorings of Mozilla codebase, like replacing out-params with return values. His main tool for code rewriting is Pork:

Pork is a C++ parsing and rewriting
tool chain. The core of Pork is a C++
parser that provides exact character
positions for the start and end of
every AST node, as well as the set of
macro expansions that contain any
location. This information allows C++
to be automatically rewritten in a
precise way.

From the blog:

So far pork has been used for “minor”
things like renaming
classes&functions, rotating
outparameters and correcting prbool
bugs. Additionally, Pork proved itself
in an experiment which involved
rewriting almost every function (ie
generating a 3+MB patch) in Mozilla to
use garbage collection instead of
reference-counting.

It is for C++, but it may suit your needs.

迷爱 2024-07-21 07:54:47

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

这一切的难点在于构建的巨大能量
1) 2) 3)。 您无法证明任何单独的清理任务是合理的。
能做的就是专门建设这样的基础设施
其目标是将其分摊到许多不同的项目上
程序分析和转换任务。

我的公司提供这样一个工具:DMS Software Reengineering
工具包。 看
http://www.semdesigns.com/Products/DMS/DMSToolkit.html
DMS 拥有多种语言的生产质量前端,
包括 C、C++、Java 和 COBOL。

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

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

我们没有提及的一种情况是“无用参数”
案例,因为要删除一个无用的参数,你有
查找来自其他模块的所有调用,
验证设置的论点没有一方
效果,并剔除无用的论点。
事实上我们有整个软件的完整图表
利益系统,所以这也将是
可能的。

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

One of the posters above says "impossible and inadvisable".
Another says "tricky", which is the right answer.
You need 1) a full C (or whatever language of interest) parser,
2) inference procedures that understand the language
identifier references and data flows to determine that a variable
is indeed "dead", and 3) the ability to actually modify
the source code.

What's hard about all this is the huge energy to build
1) 2) 3). You can't justify for any individual cleanup task.
What one can do is to build such infrastructure specifically
with the goal of amortizing it across lots of differnt
program analysis and transformation tasks.

My company offers such a tool: The DMS Software Reengineering
Toolkit. See
http://www.semdesigns.com/Products/DMS/DMSToolkit.html
DMS has production quality front ends for many languages,
including C, C++, Java and COBOL.

We have in fact built an automated "find useless declarations"
tool for Java that does two things:
a) lists them all (thus producing the list!)
b) makes a copy of the code with the useless declarations
removed.
You choose which answer you want to keep :-)

To do the same for C would not be difficult. We already
have a tool that identifies such dead variables/functions.

One case we did not addess, is the "useless parameter"
case, becasue to remove a useless parameter, you have
to find all the calls from other modules,
verify that setting up the argument doesn't have a side
effect, and rip out the useless argument.
We in fact have full graphs of the entire software
system of interest, and so this would also be
possible.

So, its just tricky, and not even very tricky
if you have the right infrastructure.

肤浅与狂妄 2024-07-21 07:54:47

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

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

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

You can solve the problem as a text processing problem. There must be a small number of regexp patterns how unused local variables are defined in the source code.

Using a list of unused variable names and the line numbers where they are, You can process the C source code line-by-line. On each line You can iterate over the variable names. On each variable name You can match the patterns one-by-one. After a successful match You know the syntax of the definition, so You know how to delete the unused variable from it.

For example if the source line is: "int a, unused, b;" and the compiler reported "unused" as an unused variable in that line, than the pattern "/, unused,/" will match and You can replace that substring with a single ",".

骑趴 2024-07-21 07:54:47

另外:夹板

Splint 是一个静态检查 C 程序安全漏洞和编码错误的工具。 只需最少的努力,Splint 就可以用作更好的 lint。 如果投入额外的精力向程序添加注释,Splint 可以执行比任何标准 lint 更强大的检查。

Also: splint.

Splint is a tool for statically checking C programs for security vulnerabilities and coding mistakes. With minimal effort, Splint can be used as a better lint. If additional effort is invested adding annotations to programs, Splint can perform stronger checking than can be done by any standard lint.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文