我正在清理一些C代码。到处都有全局变量,但并非所有变量都被使用。我想清理那些。但是逐一测试它们太过分了。有没有简单的方法呢?
答案 0 :(得分:6)
您可以使用非常有用的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 points out),但它应该是一个好的开始。
答案 1 :(得分:3)
如果它们仅在文件中使用,则可以将它们声明为“静态”,如果从未使用它们,GCC将发出警告。
如果它们是从多个文件中使用的...我不知道除了grepping或使用IDE之外你怎么能检测到它,因为它们会显示为链接符号,理论上可以被任何代码访问与您的代码链接...
答案 2 :(得分:3)
此答案适用于原始问题。随后问题已经改变了。
原则上不可能确定是使用还是需要全局变量。构造函数可能会产生副作用,因此即使永远不会访问全局,也可能需要它。
真实的故事:保持无名的程序员从生产应用程序中删除了“未使用的”全局。不幸的是,来自分配器的全局分配内存的构造函数在初始化时初始化。
由于他删除了未使用的全局,使用该分配器创建的下一个对象导致分配器初始化。不幸的是,初始化不是线程安全的(并且清楚地记录了这一点) - 全局的目的是确保在创建任何线程之前初始化它。
我们只是说有非常糟糕的后果(涉及该公司最大的客户 - 一个着名的三字母政府机构),并将其留在那里。
人类必须确定全球不需要仅因为未使用而被创建,这可能是一个非常复杂的决策。
答案 3 :(得分:2)
容易吗?对于全局变量X,您需要扫描代码中的每个编译单元,以便可以访问X(读取,写入或生成引用)。如果没有这样的访问,那么您可以合理地确定(您没有任何汇编代码,对吧?)X未被使用。
甚至可能是以上述方式之一引用X 的情况,但实际上对程序没有实际影响(例如,X被读取但忽略,写入但未读取,地址,但从未取消引用)。这使得X有效地死了。确定这一点需要进行全球数据流分析。
答案 4 :(得分:1)
(@ ChrisLutz将这个想法作为评论发布了,但是在我阅读评论之前我已经想到了它,所以无论如何我都会发布它。我会尝试通过扩展它来增加一些价值。)
在源代码的单独副本中,注释掉所有全局变量的声明并重新编译所有内容。将您注释掉的变量列表与编译器错误消息中提到的变量列表进行比较。错误消息中未提及的任何内容都未使用。
请注意,您的构建过程可能不会尝试构建某些编译失败的所有内容,因此可能会给您一些不完整的结果。
避免此问题的略微不同的方法是迭代的:注释掉所有的全局变量,尝试构建,然后取消注释编译器抱怨的任何声明。迭代直到你得到一个干净的构建,并看看还有什么评论。
答案 5 :(得分:0)
Doxygen可能会为您提供全局变量的使用列表。