有没有办法识别 C 项目中所有未使用的全局变量?

发布于 2024-12-12 22:38:06 字数 79 浏览 5 评论 0原文

我正在清理一些 C 代码。到处都有全局变量,但并不是所有的都被使用。我想清理那些。但要一一测试它们的工作量太大。有没有简单的方法可以做到这一点?

I'm cleaning up some C code. There are global variables everywhere, but not all of them are used. I want to clean up those. But it's too much work to test them one by one. Is there are easy way to do that?

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

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

发布评论

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

评论(6

赢得她心 2024-12-19 22:38:06

您可以使用非常有用的 ctags(1) 命令和 -x 命令行选项来生成目录中所有全局变量的列表:

ctags  -x  --c-kinds=v  --file-scope=no *.c

这可以与也-有用的 gid(1) 命令(假设您首先在源上运行 mkid(1)):

for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done

这为您提供了哪些文件使用哪些全局变量的有用列表:

$ for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done
basedir        parser.h ./{parser_include,parser_main}.c
binary_input   parser_main.c
cache_fd       parser.h ./{parser_interface,parser_main}.c
conf_quiet     parser.h parser_main.c
conf_verbose   parser.h ./{parser_interface,parser_main}.c
...

它并不完美(如 Ira 积分出),但这应该是一个好的开始。

You can generate a list of all global variables in your directory using the very helpful ctags(1) command with the -x command line option:

ctags  -x  --c-kinds=v  --file-scope=no *.c

This can be combined with the also-helpful gid(1) command (assuming you've run mkid(1) on your sources first):

for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done

This gives you a helpful list of which files use which globals:

$ for name in `ctags  -x  --c-kinds=v  --file-scope=no *.c | awk '{print $1;}' | sort -u` ; do gid -R filenames $name ; done
basedir        parser.h ./{parser_include,parser_main}.c
binary_input   parser_main.c
cache_fd       parser.h ./{parser_interface,parser_main}.c
conf_quiet     parser.h parser_main.c
conf_verbose   parser.h ./{parser_interface,parser_main}.c
...

It isn't perfect (as Ira points out), but it should be a good start.

冷心人i 2024-12-19 22:38:06

如果它们仅在文件中使用,您可以将它们声明为“静态”,并且如果从未使用它们,GCC 将发出警告。

如果它们从多个文件中使用...我不知道除了 grep 或使用 IDE 之外,您如何检测到它们,因为它们将显示为链接器符号,并且理论上可以由与您链接的任何代码访问代码...

If they are only used within the file, you can declare them "static" and GCC will warn if they are never used.

If they are used from multiple files... I'm not sure how you could detect that, other than grepping or using an IDE, because they will show up as linker symbols and could in theory be accessed by any code that links with your code...

没有你我更好 2024-12-19 22:38:06

此答案适用于原始问题。问题随后被更改。

原则上不可能确定是否使用或需要全局变量。构造函数可能会产生副作用,因此即使从未访问过全局变量,也可能仍然需要它。

真实故事:匿名的程序员从生产应用程序中删除了“未使用”的全局变量。不幸的是,该全局分配内存的构造函数是在第一次分配时初始化的分配器。

由于他删除了未使用的全局变量,使用该分配器创建的下一个对象导致分配器初始化。不幸的是,初始化不是线程安全的(并且有明确的记录)——全局的目的是确保它在创建任何线程之前初始化。

我们只能说,后果非常严重(涉及该公司最大的客户——一家著名的三字母政府机构),然后就这样吧。

人类必须做出决定,不需要仅仅因为全局未使用而创建它,而这可能是一个非常复杂的决定。

This answer applies to the original question. The question has subsequently been changed.

It is impossible in principle to determine if a global variable is used or needed. Constructors can have side-effects, so even if a global is never accessed, it may still be needed.

True story: Programmer who shall remain nameless removed an 'unused' global from a production application. Unfortunately, the constructor for that global allocated memory from an allocator that initializes on first allocation.

As a result of him removing the unused global, the next object created using that allocator caused the allocator to initialize. Unfortunately, the initialization wasn't thread-safe (and was clearly documented as such) -- the purpose of the global was to ensure it initialized before any threads were created.

Let's just say there were very bad consequences (involving this company's largest customer -- a well-known three-letter government agency) and leave it at that.

A human being must make the determination that a global does not need to be created just because it is unused, and that can be a remarkably complicated decision to make.

三生路 2024-12-19 22:38:06

简单的?不可以。对于全局变量 X,您需要扫描代码中的每个编译单元以获取对 X 的潜在访问(读取、写入或生成引用)。如果没有这样的访问,那么您可以合理地确定(您没有任何汇编代码,对吧?)X 未被使用。

甚至可能出现这样的情况:X以上述方式之一引用,但实际上对程序没有实际影响(例如,X被读取但忽略,写入但不读取,地址被占用)但从未取消引用)。这实际上让 X 死了。确定这一点需要全局数据流分析。

Easy? No. For a global variable X, you need to scan every compilation unit in your code for a potential access to X (a read, a write, or the generation of a reference). If there are no such accesses, then you can be reasonably sure (you don't have any assembly code, right?) that X isn't used.

It may even be the case that X is referenced in one of the above ways, but in fact has no actual effect on the program (e.g., X is read but ignore, written but not read, address taken but never dereferenced). That makes X effectively dead. Determining this requires global data flow analysis.

毁我热情 2024-12-19 22:38:06

(@ChrisLutz 将这个想法作为评论发布,但我在阅读评论之前就想到了它,所以无论如何我都会发布它。我会尝试通过扩展它来增加一些价值。)

在您的单独副本中源代码,注释掉所有全局变量的声明并重新编译所有内容。将注释掉的变量列表与编译器错误消息中提到的变量列表进行比较。错误消息中未提及的任何内容均未使用。

请注意,您的构建过程可能不会尝试构建某些编译失败的所有内容,因此可能会给出一些不完整的结果。

避免此问题的一种稍微不同的方法是迭代方法:注释掉所有全局变量,尝试构建,然后取消注释编译器抱怨的任何内容的声明。迭代直到获得一个干净的构建,并查看仍然注释掉的内容。

(@ChrisLutz posted this idea as a comment, but I thought of it before I read the comment so I'm going to post it anyway. I'll try to add some value by expanding on it.)

In a separate copy of your source code, comment out the declarations of all your global variables and recompile everything. Compare the list of variables you commented out to the ones mentioned in compiler error messages. Anything not mentioned in an error message is unused.

Note that your build process might not try to build everything of some compilations fail, so that could give you some incomplete results.

A slightly different approach that avoids this problem is an iterative one: comment out all your globals, try to build, then uncomment the declarations for anything that the compiler complained about. Iterate until you get a clean build, and see what's still commented out.

初心未许 2024-12-19 22:38:06

Doxygen 或许能够为您提供全局变量的用途列表。

Doxygen may be able to give you a list of uses for global variables.

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