[英]Locate unused structures and structure-members
前一段時間我們接管了遺留代碼庫的責任。
這個非常糟糕的結構/編寫代碼的一個怪癖是它包含許多非常龐大的結構,每個結構包含數百個成員。 我們所做的許多步驟之一是清除盡可能多的未使用的代碼,因此需要找到未使用的結構/結構成員。
關於結構,我想出了python, GNU Global和ctags的組合來列出未使用的結構成員。
基本上,我正在做的是使用ctags
生成一個標簽文件,下面的python腳本解析該文件以找到所有結構成員,然后使用GNU Global
在先前生成的全局數據庫中進行查找,看看是否存在成員用於代碼中。
這種方法存在許多相當嚴重的缺陷,但它解決了我們面臨的問題,並為我們進一步清理提供了良好的開端。
必須有更好的方法來做到這一點!
問題是:如何在代碼庫中找到未使用的結構和結構成員?
#!/usr/bin/env python
import os
import string
import sys
import operator
def printheader(word):
"""generate a nice header string"""
print "\n%s\n%s" % (word, "-" * len(word))
class StructFreqAnalysis:
""" add description"""
def __init__(self):
self.path2hfile=''
self.name=''
self.id=''
self.members=[]
def show(self):
print 'path2hfile:',self.path2hfile
print 'name:',self.name
print 'members:',self.members
print
def sort(self):
return sorted(self.members, key=operator.itemgetter(1))
def prettyprint(self):
'''display a sorted list'''
print 'struct:',self.name
print 'path:',self.path2hfile
for i in self.sort():
print ' ',i[0],':',i[1]
print
f=open('tags','r')
x={} # struct_name -> class
y={} # internal tags id -> class
for i in f:
i=i.strip()
if 'typeref:struct:' in i:
line=i.split()
x[line[0]]=StructFreqAnalysis()
x[line[0]].name=line[0]
x[line[0]].path2hfile=line[1]
for j in line:
if 'typeref' in j:
s=j.split(':')
x[line[0]].id=s[-1]
y[s[-1]]=x[line[0]]
f.seek(0)
for i in f:
i=i.strip()
if 'struct:' in i:
items=i.split()
name=items[0]
id=items[-1].split(':')[-1]
if id:
if id in y:
key=y[id]
key.members.append([name,0])
f.close()
# do frequency count
for k,v in x.iteritems():
for i in v.members:
cmd='global -a -s %s'%i[0] # -a absolute path. use global to give src-file for member
g=os.popen(cmd)
for gout in g:
if '.c' in gout:
gout=gout.strip()
f=open(gout,'r')
for line in f:
if '->'+i[0] in line or '.'+i[0] in line:
i[1]=i[1]+1
f.close()
printheader('All structures')
for k,v in x.iteritems():
v.prettyprint()
#show which structs that can be removed
printheader('These structs could perhaps be removed')
for k,v in x.iteritems():
if len(v.members)==0:
v.show()
printheader('Total number of probably unused members')
cnt=0
for k,v in x.iteritems():
for i in v.members:
if i[1]==0:
cnt=cnt+1
print cnt
編輯
正如@ Jens-Gustedt所提出的,使用編譯器是一種很好的方法。 在使用編譯器方法之前,我正在采用一種可以進行某種“高級”過濾的方法。
雖然這是一個很老的帖子。 但最近我使用python和gdb做了同樣的事情。 我編譯了以下代碼片段,其結構位於層次結構的頂部,然后使用gdb在結構上執行打印類型並重新詛咒其成員。
#include <usedheader.h>
UsedStructureInTop *to_print = 0;
int main(){return 0;}
(gdb) p to_print
(gdb) $1 = (UsedStructureInTop *) 0x0
(gdb) pt UsedStructureInTop
type = struct StructureTag {
members displayed here line by line
}
(gdb)
雖然我的目的沒什么不同。 它是生成一個只包含結構UsedStructureInTop及其依賴類型的頭。 有編譯器選項可以執行此操作。 但是它們不會刪除包含的頭文件中找到的未使用/未鏈接的結構。
如果這些只是一些struct
並且如果代碼沒有通過另一種類型訪問struct
糟糕黑客...那么你可以只注釋掉你的第一個struct
所有字段並讓編譯器告訴你。
取消注釋一個二次使用的字段,直到編譯器滿意為止。 然后,一旦編譯,進行良好的測試,以確保沒有黑客的前提條件。
迭代所有struct
。
絕對不是很漂亮,但最后你至少有一個人知道代碼。
使用覆蓋率 。 這是檢測代碼缺陷的絕佳工具,但成本有點高。
在C規則下,可以通過具有類似布局的另一個結構訪問struct成員。 這意味着你可以訪問struct Foo {int a; float b; char c; };
struct Foo {int a; float b; char c; };
通過struct Bar { int x; float y; };
struct Bar { int x; float y; };
(當然除了Foo::c
)。
因此,您的算法可能存在缺陷。 很難找到你想要的東西,這就是為什么C很難優化的原因。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.