簡體   English   中英

找到未使用的結構和結構成員

[英]Locate unused structures and structure-members

前一段時間我們接管了遺留代碼庫的責任。

這個非常糟糕的結構/編寫代碼的一個怪癖是它包含許多非常龐大的結構,每個結構包含數百個成員。 我們所做的許多步驟之一是清除盡可能多的未使用的代碼,因此需要找到未使用的結構/結構成員。

關於結構,我想出了python, GNU Globalctags的組合來列出未使用的結構成員。

基本上,我正在做的是使用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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM