मुझे कैसे पता चलेगा कि कोड में कौन से हिस्से कभी उपयोग नहीं किए जाते हैं?


312

मेरे पास विरासत C ++ कोड है जिसे मैं अप्रयुक्त कोड को हटाने वाला हूं। समस्या यह है कि कोड आधार बड़ा है।

मैं कैसे पता लगा सकता हूं कि किस कोड को कभी नहीं कहा जाता है / कभी उपयोग नहीं किया जाता है?


4
मुझे लगता है कि एक कोड क्वेरी भाषा आपको एक पूरे के रूप में अपनी परियोजना का एक बेहतर दृश्य देगी। मुझे सी ++ दुनिया के बारे में निश्चित नहीं है लेकिन लगता है कि यह cppdepend.com (यह मुफ़्त नहीं है), जो काफी सभ्य दिखता है। हो सकता है कि कुछ ऐसा हो जो मुफ्त में उपलब्ध हो। दूसरी बात यह है कि रिफैक्टिंग के किसी भी प्रकार को करने से पहले, यदि आपके पास अभी परीक्षण नहीं है, तो यह करने के लिए महत्वपूर्ण बात यूनिट टेस्ट होगी। इकाई परीक्षणों के साथ आप क्या कर सकते हैं आपके कोड कवरेज टूल आपके कोड को प्रोफाइल करते हैं जो स्वयं उस मृत कोड को हटाने में मदद करेंगे यदि आप उस कोड को कवर नहीं कर सकते हैं।
बिस्वनाथ

3
यहां संदर्भ देखें: en.wikipedia.org/wiki/Unreachable_code
मार्टिन

6
मुझे इसी तरह का विषय लगता है। stackoverflow.com/questions/229069/…
उम्मा गुम्मा

3
हाँ, C ++ की मज़ेदार बातों में से एक यह है कि "अप्रयुक्त" फ़ंक्शंस को हटाने से प्रोग्राम का परिणाम बदल सकता है।
MSalters

1
@MSalters: यह एक दिलचस्प है ... उस मामले के लिए हमें एक बात करनी होगी कि किसी दिए गए कॉल के लिए एक अधिभार सेट में किस फ़ंक्शन को चुना जाता है, सही है? मेरी जानकारी के अनुसार, यदि दोनों नाम वाले 2 कार्य हैं f(), और f()अनायास ही एक कॉल 1 के लिए हल हो जाती है, तो यह संभव नहीं है कि केवल 2 नाम के 3 फ़ंक्शन को जोड़कर उस कॉल को 2 पर हल करें f()- "सबसे खराब आप कर सकते हैं" "उस 3 फंक्शन को जोड़ने से कॉल अस्पष्ट हो जाता है और इसलिए प्रोग्राम को संकलित होने से रोकता है। एक प्रतिपक्ष को देखने के लिए प्यार (= भयभीत) होगा।
j_random_hacker

जवाबों:


197

अप्रयुक्त कोड की दो किस्में हैं:

  • स्थानीय एक, अर्थात्, कुछ कार्यों में कुछ पथ या चर अप्रयुक्त होते हैं (या उपयोग किए जाते हैं लेकिन कोई सार्थक तरीके से नहीं, जैसे लिखित लेकिन कभी पढ़ा नहीं जाता)
  • वैश्विक एक: फ़ंक्शंस जिन्हें कभी नहीं कहा जाता है, वैश्विक ऑब्जेक्ट जो कभी एक्सेस नहीं होते हैं

पहली तरह के लिए, एक अच्छा संकलक मदद कर सकता है:

  • -Wunused(जीसीसी, क्लैंग ) को अप्रयुक्त चर के बारे में चेतावनी दी जानी चाहिए, क्लैंग अप्रयुक्त विश्लेषक को उन चरों के बारे में चेतावनी देने के लिए भी बढ़ा दिया गया है जो कभी पढ़े नहीं जाते हैं (भले ही उपयोग किए जाते हैं)।
  • -Wunreachable-code(पुराने जीसीसी, 2010 में हटाए गए ) को उन स्थानीय ब्लॉकों के बारे में चेतावनी देनी चाहिए जो कभी एक्सेस नहीं होते हैं (यह शुरुआती रिटर्न या शर्तों के साथ होता है जिन्हें हमेशा समझना चाहिए)
  • मेरे पास अप्रयुक्त के बारे में चेतावनी देने के लिए कोई विकल्प नहीं है catch ब्लॉकों के , क्योंकि संकलक आमतौर पर यह साबित नहीं कर सकता है कि कोई अपवाद नहीं फेंका जाएगा।

दूसरी तरह के लिए, यह बहुत अधिक कठिन है। सांख्यिकीय रूप से इसे पूरे कार्यक्रम के विश्लेषण की आवश्यकता होती है, और भले ही लिंक टाइम ऑप्टिमाइज़ेशन वास्तव में मृत कोड को हटा सकता है, लेकिन व्यवहार में कार्यक्रम को प्रदर्शन के समय इतना बदल दिया गया है कि उपयोगकर्ता को सार्थक जानकारी देना असंभव है।

इसलिए दो दृष्टिकोण हैं:

  • सिद्धांतवादी एक स्थिर विश्लेषक का उपयोग करना है। सॉफ्टवेयर का एक टुकड़ा जो पूरे कोड की एक बार में बहुत विस्तार से जांच करेगा और सभी प्रवाह पथों का पता लगाएगा। व्यवहार में मुझे यह नहीं पता कि यहां कोई काम करेगा।
  • व्यावहारिक एक हेयुरिस्टिक का उपयोग करना है: एक कोड कवरेज टूल का उपयोग करें (यह जीएनयू श्रृंखला में है gcov। ध्यान दें कि इसे ठीक से काम करने के लिए संकलन के दौरान विशिष्ट झंडे पारित किए जाने चाहिए)। आप विभिन्न इनपुट्स (आपके यूनिट-परीक्षण या गैर-प्रतिगमन परीक्षण) के एक अच्छे सेट के साथ कोड कवरेज टूल चलाते हैं, मृत कोड आवश्यक रूप से अप्राप्त कोड के भीतर है ... और इसलिए आप यहां से शुरू कर सकते हैं।

यदि आप इस विषय में बहुत रुचि रखते हैं, और वास्तव में अपने आप से एक उपकरण को काम करने के लिए समय और झुकाव है, तो मैं इस तरह के उपकरण के निर्माण के लिए क्लैंग पुस्तकालयों का उपयोग करने का सुझाव दूंगा।

  1. AST प्राप्त करने के लिए क्लैंग लाइब्रेरी का उपयोग करें (सार सिंटैक्स ट्री)
  2. आगे के प्रवेश बिंदुओं से एक मार्क-एंड-स्वीप विश्लेषण करें

क्योंकि क्लैंग आपके लिए कोड पार्स करेगा, और ओवरलोड रिज़ॉल्यूशन करेगा, आपको सी ++ भाषाओं के नियमों से निपटने की ज़रूरत नहीं होगी, और आप हाथ में समस्या पर ध्यान केंद्रित करने में सक्षम होंगे।

हालाँकि, इस तरह की तकनीक उन अप्रभावी वर्चुअल ओवरराइड्स की पहचान नहीं कर सकती है, क्योंकि उन्हें तीसरे पक्ष के कोड द्वारा बुलाया जा सकता है, जिनके बारे में आप कारण नहीं बता सकते।


7
बहुत अच्छा, +1। मुझे यह पसंद है कि आप उस कोड के बीच अंतर करते हैं जो किसी भी परिस्थिति में और कभी भी किसी विशेष रन में नहीं चलने वाले कोड के तहत कभी भी न चलने के लिए निर्धारित किया जा सकता है, लेकिन संभवतः हो सकता है। पूर्व महत्वपूर्ण है जो मुझे लगता है, और जैसा कि आप कहते हैं कि पूरे कार्यक्रम के एएसटी का उपयोग करके एक रीचबिलिटी विश्लेषण इसे प्राप्त करने का तरीका है। ( foo()जब इसे केवल " if (0) { foo(); }बोनस " के रूप में चिह्नित किया जा रहा है, तो यह एक बोनस होगा, लेकिन अतिरिक्त स्मार्ट की आवश्यकता होगी।)
j_random_hacker

@j_random_hacker: शायद कि CFG (कंट्रोल-फ्लो ग्राफ) का उपयोग करने से अब बेहतर होगा कि मैं इसके बारे में सोचूं (आपके उदाहरण के लिए धन्यवाद)। मुझे पता है कि क्लैंग ने आपके द्वारा बताए गए जैसे तांत्रिक तुलनाओं के बारे में टिप्पणी करने के लिए उत्सुक है और इस प्रकार सीएफजी का उपयोग करके हम संभवतः मृत-कोड को जल्दी से देख सकते हैं।
मैथ्यू एम।

@ मैथ्यू: हाँ शायद सीएफजी का मेरा मतलब है कि एएसटी के बजाय मेरा भी मतलब है: मेरा मतलब क्या है: एक डाइग्राफ जिसमें फंक्शंस होते हैं और फंक्शन x से फंक्शन y तक एक बढ़त होती है जब भी x संभवतया y को कॉल कर सकता है। (और महत्वपूर्ण संपत्ति के साथ जो अतिभारित कार्यों में सभी को अलग-अलग
दिशाओं

1
@j_random_hacker: वास्तव में सीएफजी एक साधारण डिग्राफ की तुलना में अधिक जटिल है, क्योंकि यह सशर्त बयानों के आधार पर एक ब्लॉक से दूसरे ब्लॉक के लिंक वाले ब्लॉक में निष्पादित होने वाले सभी कोड का प्रतिनिधित्व करता है। मुख्य लाभ यह है कि यह स्वाभाविक रूप से pruning कोड के लिए अनुकूल है जो सांख्यिकीय रूप से मृत होने के लिए निर्धारित किया जा सकता है (यह पहचान योग्य ब्लॉक बनाता है जिसे पहचाना जा सकता है), इसलिए यह बेहतर होगा कि आप खुदाई करने के लिए एएसटी की तुलना में सीएफजी का शोषण करें। के बारे में बात कर रहा हूँ ... मुझे लगता है :)
Matthieu M.

1
@j_random_hacker: वास्तव में क्लैंग का एएसटी करता है, यह सब कुछ स्पष्ट (या लगभग ...) करता है क्योंकि यह कोड के साथ काम करने के लिए है, न कि केवल इसे संकलित करने के लिए। इस समय वास्तव में एक चर्चा है क्योंकि जाहिरा तौर पर इनिशियलाइज़र सूचियों के साथ एक मुद्दा है जहां इस तरह के एक अंतर्निहित रूपांतरण एएसटी में प्रकट नहीं होता है, लेकिन मुझे लगता है कि यह तय हो जाएगा।
मैथ्यू एम।

35

अप्रयुक्त पूरे कार्यों (और अप्रयुक्त वैश्विक चर) के मामले के लिए, जीसीसी वास्तव में आपके लिए अधिकांश काम कर सकता है बशर्ते कि आप जीसीसी और जीएनयू एलडी का उपयोग कर रहे हों।

स्रोत को संकलित करते समय, उपयोग -ffunction-sectionsऔर -fdata-sections, तब लिंक को उपयोग करते समय -Wl,--gc-sections,--print-gc-sections। लिंकर अब उन सभी कार्यों को सूचीबद्ध करेगा जिन्हें हटाया जा सकता है क्योंकि उन्हें कभी भी नहीं बुलाया गया था और सभी ग्लोबल्स जिन्हें कभी भी संदर्भित नहीं किया गया था।

(बेशक, आप भी --print-gc-sectionsभाग को छोड़ सकते हैं और लिंकर को चुपचाप कार्यों को हटा सकते हैं, लेकिन उन्हें स्रोत में रख सकते हैं)।

नोट: यह केवल अप्रयुक्त पूर्ण फ़ंक्शन को खोजेगा, यह फ़ंक्शन के भीतर मृत कोड के बारे में कुछ भी नहीं करेगा। लाइव फ़ंक्शंस में डेड कोड से बुलाए गए फ़ंक्शंस को भी रखा जाएगा।

कुछ C ++ - विशिष्ट विशेषताएं भी विशेष रूप से समस्याएं पैदा करेंगी:

  • आभासी कार्य। यह जानने के बिना कि कौन से उपवर्ग मौजूद हैं और जो वास्तव में रन टाइम पर त्वरित हैं, आप यह नहीं जान सकते हैं कि अंतिम कार्यक्रम में आपको कौन से वर्चुअल फ़ंक्शंस की आवश्यकता है। लिंकर के पास इस बारे में पर्याप्त जानकारी नहीं होती है, इसलिए उसे उन सभी को अपने आसपास रखना होगा।
  • कंस्ट्रक्टर और उनके कंस्ट्रक्टर के साथ ग्लोबल्स। सामान्य तौर पर, लिंक करने वाला यह नहीं जान सकता है कि किसी वैश्विक निर्माता के साइड इफेक्ट्स नहीं होते हैं, इसलिए उसे इसे चलाना होगा। जाहिर है इसका मतलब है कि वैश्विक स्तर पर भी इसे बनाए रखने की जरूरत है।

दोनों ही मामलों में, वर्चुअल फ़ंक्शन या ग्लोबल-वैरिएबल कंस्ट्रक्टर द्वारा उपयोग की जाने वाली किसी भी चीज़ को आसपास रखना होगा।

एक अतिरिक्त चेतावनी यह है कि यदि आप एक साझा लाइब्रेरी का निर्माण कर रहे हैं, तो जीसीसी में डिफ़ॉल्ट सेटिंग्स साझा लाइब्रेरी में प्रत्येक फ़ंक्शन को निर्यात करेंगी , क्योंकि इससे लिंकर का संबंध "उपयोग" होगा। यह तय करने के लिए कि आपको निर्यात (उदाहरण के लिए -fvisibility=hidden) के बजाय प्रतीकों को छिपाने के लिए डिफ़ॉल्ट सेट करने की आवश्यकता है , और फिर उन निर्यात किए गए कार्यों का स्पष्ट रूप से चयन करें जिन्हें आपको निर्यात करने की आवश्यकता है।


महान व्यावहारिक सलाह। बस उन कार्यों की एक सूची प्राप्त करना जो ज्ञात हैं कि कहीं भी उपयोग नहीं किया जाना है (भले ही, जैसा कि आप कहते हैं, यह सूची पूरी नहीं है) मुझे लगता है कि कम-फांसी फल का एक बहुत कुछ मिलेगा।
j_random_hacker

मैं इस काम करता है में से किसी के लिए नहीं लगता है uninstantiated टेम्पलेट्स
याकूब किलिकोवस्की

25

वैसे अगर आप g ++ का उपयोग कर रहे हैं तो आप इस ध्वज का उपयोग कर सकते हैं -Wunused

प्रलेखन के अनुसार:

चेतावनी दें कि जब भी कोई चर अपनी घोषणा से अलग होता है, जब भी कोई फ़ंक्शन स्थिर घोषित किया जाता है, लेकिन कभी भी परिभाषित नहीं किया जाता है, जब भी कोई लेबल घोषित किया जाता है, लेकिन इसका उपयोग नहीं किया जाता है, और जब भी कोई कथन ऐसे परिणाम की गणना करता है जिसका स्पष्ट रूप से उपयोग नहीं किया जाता है।

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

संपादित करें : यहाँ -Wunreachable-code प्रलेखन के अनुसार अन्य उपयोगी ध्वज है :

यह विकल्प चेतावनी देने के लिए अभिप्रेत है जब संकलक यह पता लगाता है कि कम से कम स्रोत कोड की एक पूरी पंक्ति कभी क्रियान्वित नहीं होगी, क्योंकि कुछ स्थिति कभी संतुष्ट नहीं होती है या क्योंकि यह एक ऐसी प्रक्रिया के बाद होती है जो कभी नहीं लौटती है।

अपडेट : मुझे विरासत सी / सी ++ प्रोजेक्ट में इसी तरह का विषय डेड कोड डिटेक्शन मिला


4
यह हेडर को नहीं पकड़ेगा जो प्रोटोटाइप फ़ंक्शंस हैं जिन्हें कभी नहीं कहा जाता है। या सार्वजनिक वर्ग के तरीके जिन्हें बुलाया नहीं जाता है। यह तभी जांच सकता है कि उस दायरे में स्थानीय रूप से स्कोप किए गए चर का उपयोग किया जाता है या नहीं।
फल्मरी

@Falmarri मैंने कभी इस झंडे का इस्तेमाल नहीं किया। मैं खुद यह पता लगाने की कोशिश कर रहा हूं कि मुझे किस तरह के डेड कोड मिल सकते हैं।
उम्मागुम्मा २ '

-Wunusedउन चरों के बारे में चेतावनी देता है जो घोषित (या एक ही बार में घोषित और परिभाषित) हैं लेकिन वास्तव में कभी उपयोग नहीं किए जाते। इस तरह से स्कॉप्ड गार्ड के साथ बहुत गुस्सा: पी क्लेंग में एक प्रायोगिक कार्यान्वयन है यह गैर-वाष्पशील चरों के लिए भी चेतावनी दी गई है जो कि लिखे गए हैं लेकिन टेड क्रेमेनेक से कभी नहीं पढ़े जाते हैं। -Wunreachable-codeएक फ़ंक्शन के भीतर कोड के बारे में चेतावनी दी गई है, जो नहीं पहुंच सकता है, यह कोड throwया returnस्टेटमेंट या किसी शाखा में कोड के बाद स्थित हो सकता है जिसे कभी भी नहीं लिया जाता है (जो कि तुलनात्मक तुलना के मामले में होता है)।
मथिउ एम।

18

मुझे लगता है कि आप एक कोड कवरेज टूल की तलाश कर रहे हैं । एक कोड कवरेज टूल आपके कोड का विश्लेषण करेगा क्योंकि यह चल रहा है, और यह आपको बताएगा कि कोड की कौन सी लाइनें निष्पादित की गईं और कितनी बार, साथ ही साथ कौन सी नहीं थीं।

आप इस ओपन सोर्स कोड कवरेज टूल को मौका देने का प्रयास कर सकते हैं: TestCocoon - C / C ++ और C # के लिए कोड कवरेज टूल।


7
यहां कुंजी "जैसा कि यह चल रहा है" है - यदि आपका इनपुट डेटा कुछ कोड पथ का उपयोग नहीं करता है तो उस पथ को उपयोग के रूप में पहचाना नहीं जाएगा, क्या यह होगा?
शार्पूथ

1
वह सही है। कोड को चलाए बिना यह जानने का कोई तरीका नहीं है कि किन लाइनों तक नहीं पहुंचा जा रहा है। मुझे आश्चर्य है कि कुछ सामान्य रनों का अनुकरण करने के लिए कुछ यूनिट टेस्ट स्थापित करना कितना कठिन होगा।
कार्लोस वी।

1
@drishch मुझे लगता है, कि इस तरह के अप्रयुक्त कोड को लिंकर और कंपाइलर नहीं ढूंढना चाहिए।
उम्मगम्मा

1
@drirsch यह सच है कि संकलक कुछ ऐसे कोड का ध्यान रख सकता है जो अनुपलब्ध है, जैसे कि फ़ंक्शन घोषित किए जा रहे हैं, लेकिन कॉल नहीं किए जाते हैं और कुछ शॉर्ट सर्किट मूल्यांकन होते हैं, लेकिन कोड के बारे में क्या है जो उपयोगकर्ता की कार्रवाई पर निर्भर करता है, या समय चर चलाते हैं?
कार्लोस वी।

1
@golcarcol ठीक है, चलो हमारे पास void func()a.cpp में कार्य करते हैं, जिसका उपयोग b.cpp में किया जाता है। कंपाइलर कैसे जांच सकता है, उस फंक () का उपयोग प्रोग्राम में किया जाता है? यह लिंकर्स का काम है।
उम्मगम्मा २ 27'११ को

15

यहाँ असली जवाब है: आप वास्तव में कभी नहीं जान सकते।

कम से कम, nontrivial मामलों के लिए, आप यह सुनिश्चित नहीं कर सकते कि आपने यह सब प्राप्त कर लिया है। अगम्य कोड पर विकिपीडिया के लेख से निम्नलिखित पर विचार करें :

double x = sqrt(2);
if (x > 5)
{
  doStuff();
}

विकिपीडिया सही रूप से नोट करता है, एक चतुर कंपाइलर कुछ इस तरह से पकड़ने में सक्षम हो सकता है। लेकिन एक संशोधन पर विचार करें:

int y;
cin >> y;
double x = sqrt((double)y);

if (x != 0 && x < 1)
{
  doStuff();
}

क्या कंपाइलर इसे पकड़ पाएंगे? शायद। लेकिन ऐसा करने के लिए, इसे sqrtलगातार स्केलर मान के विरुद्ध चलाने से अधिक करने की आवश्यकता होगी । यह पता लगाना (double)yहोगा कि हमेशा एक पूर्णांक (आसान) होगा, और फिर sqrtपूर्णांक (हार्ड) के सेट के लिए गणितीय सीमा को समझेंगे । एक बहुत ही परिष्कृत कंपाइलर sqrtफंक्शन के लिए या मैथ.एच में हर फंक्शन के लिए या किसी भी फिक्स्ड-इनपुट फंक्शन के लिए सक्षम हो सकता है , जिसका डोमेन यह पता लगा सकता है। यह बहुत, बहुत जटिल हो जाता है, और जटिलता मूल रूप से असीम है। आप अपने संकलक में परिष्कार की परतें जोड़ते रह सकते हैं, लेकिन हमेशा कुछ कोड में छलनी करने का एक तरीका होगा जो किसी भी इनपुट के सेट के लिए अगम्य होगा।

और फिर इनपुट सेट हैं जो बस कभी भी प्रवेश नहीं करते हैं। इनपुट जो वास्तविक जीवन में कोई मतलब नहीं होगा, या कहीं और सत्यापन तर्क द्वारा अवरुद्ध हो जाएगा। कंपाइलर के पास उन लोगों के बारे में जानने का कोई रास्ता नहीं है।

इसका अंतिम परिणाम यह है कि जब सॉफ्टवेयर टूल दूसरों ने उल्लेख किया है, तो वे बहुत उपयोगी हैं, आपको यह सुनिश्चित करने के लिए कभी नहीं जाना चाहिए कि आपने सब कुछ तब तक पकड़ा है जब तक आप मैन्युअल रूप से बाद में कोड के माध्यम से नहीं जाते हैं। फिर भी, आप कभी भी निश्चित नहीं होंगे कि आपने कुछ भी याद नहीं किया है।

एकमात्र वास्तविक समाधान, IMHO, जितना संभव हो उतना सतर्क रहना है, अपने निपटान में स्वचालन का उपयोग करें, रिफ्लेक्टर जहां आप कर सकते हैं, और लगातार अपने कोड को बेहतर बनाने के तरीकों की तलाश करें। बेशक, यह एक अच्छा विचार है कि वैसे भी है।


1
सही है और डेड कोड को मत छोड़ो! यदि आप एक सुविधा को निकालते हैं, तो मृत कोड को मार दें। इसे वहाँ छोड़ने के बाद "बस के मामले में" बस ब्लोट का कारण बनता है (जैसा कि आपने चर्चा की है) बाद में खोजना मुश्किल है। संस्करण नियंत्रण फिर से जमाखोरी करते हैं।
लाइटनेस दौड़

12

मैं इसे अपने आप उपयोग नहीं किया है, लेकिन cppcheck , दावों अप्रयुक्त कार्यों को खोजने के लिए। यह शायद पूरी समस्या को हल नहीं करेगा, लेकिन यह एक शुरुआत हो सकती है।


हां, यह स्थानीय नहीं संदर्भित चर और फ़ंक्शन खोजने में सक्षम है।
चुगिस्टर जूल

cppcheck --enable=unusedFunction --language=c++ .इन अप्रयुक्त कार्यों को खोजने के लिए हां का उपयोग करें।
जेसन हैरिस

9

आप Gimple Software से PC-lint / FlexeLint का उपयोग करने का प्रयास कर सकते हैं । यह करने का दावा करता है

पूरे प्रोजेक्ट में अप्रयुक्त मैक्रों, टाइपफेड, कक्षाएं, सदस्यों, घोषणाओं आदि का पता लगाएं

मैंने इसे स्थैतिक विश्लेषण के लिए उपयोग किया है और इसे बहुत अच्छा पाया है लेकिन मुझे यह स्वीकार करना होगा कि मैंने इसका उपयोग विशेष रूप से मृत कोड खोजने के लिए नहीं किया है।


5

अप्रयुक्त सामान खोजने के लिए मेरा सामान्य दृष्टिकोण है

  1. सुनिश्चित करें कि बिल्ड सिस्टम सही ढंग से निर्भरता ट्रैकिंग को संभालता है
  2. फ़ुल-स्क्रीन टर्मिनल विंडो के साथ एक दूसरा मॉनिटर सेट करें, बार-बार बिल्ड बनाता है और आउटपुट का पहला स्क्रीनफुल दिखा रहा है। watch "make 2>&1"यूनिक्स पर चाल करने के लिए जाता है।
  3. हर लाइन की शुरुआत में "//?" को जोड़ते हुए पूरे सोर्स ट्री पर फाइंड-एंड-रिपेयर ऑपरेशन चलाएं
  4. संकलक द्वारा ध्वजांकित पहली त्रुटि को ठीक करके, "//?" इसी लाइनों में।
  5. तब तक दोहराएं जब तक कि कोई त्रुटि शेष न हो।

यह कुछ हद तक लंबी प्रक्रिया है, लेकिन यह अच्छे परिणाम देती है।


2
योग्यता है, लेकिन बहुत श्रमसाध्य है। इसके अलावा, आपको एक ही समय में किसी फ़ंक्शन के सभी अधिभार को सुनिश्चित करने के लिए सुनिश्चित करना होगा - यदि एक से अधिक लागू है, तो एक कम-पसंद वाले को असुविधाजनक करने से संकलन सफल हो सकता है लेकिन परिणाम गलत प्रोग्राम व्यवहार में हो सकता है (और एक गलत विचार कार्यों का उपयोग किया जाता है)।
j_random_hacker

मैं केवल पहले चरण (सभी अधिभार) में घोषणाओं को अनसुना करता हूं, और अगले पुनरावृत्ति में फिर देखता हूं कि कौन सी परिभाषाएं गायब हैं; इस तरह, मैं देख सकता हूँ कि कौन से ओवरलोड वास्तव में उपयोग किए जाते हैं।
साइमन रिक्टर

@Simon: मुख्य सवाल पर एक टिप्पणी में दिलचस्प बात यह है कि, MSalters बताते हैं कि यहां तक ​​कि कभी नहीं कहा जाता है कि एक समारोह के लिए एक घोषणा की उपस्थिति / अनुपस्थिति को प्रभावित कर सकता है जो अन्य 2 कार्यों के अधिभार संकल्प द्वारा पाया जाता है। निश्चित रूप से इसके लिए एक अत्यंत विचित्र और आकस्मिक सेटअप की आवश्यकता होती है, इसलिए यह अभ्यास में समस्या होने की संभावना नहीं है।
j_random_hacker

4

संकलित त्रुटि के बिना निजी या संरक्षित के रूप में अधिक सार्वजनिक कार्यों और चर के रूप में चिह्नित करें, ऐसा करते समय, कोड को भी रीफ़्रैक्टर करने का प्रयास करें। कार्यों को निजी और कुछ हद तक संरक्षित करके, आपने अपने खोज क्षेत्र को कम कर दिया क्योंकि निजी कार्यों को केवल एक ही कक्षा से बुलाया जा सकता है (जब तक कि एक्सेस प्रतिबंध को दरकिनार करने के लिए बेवकूफ मैक्रो या अन्य चालें नहीं हैं, और यदि यह मामला है तो मैं आपको सुझाऊंगा नई नौकरी पाओ)। यह निर्धारित करना बहुत आसान है कि आपको एक निजी फ़ंक्शन की आवश्यकता नहीं है क्योंकि केवल जिस वर्ग पर आप वर्तमान में काम कर रहे हैं वह इस फ़ंक्शन को कॉल कर सकता है। यह विधि आसान है यदि आपके कोड आधार में छोटी कक्षाएं हैं और शिथिल युग्मित है। यदि आपके कोड आधार में छोटी कक्षाएं नहीं हैं या बहुत तंग युग्मन हैं, तो मैं पहले उन लोगों को साफ करने का सुझाव देता हूं।

अगला सभी शेष सार्वजनिक कार्यों को चिह्नित करने और कक्षाओं के बीच संबंध का पता लगाने के लिए एक कॉल ग्राफ बनाना होगा। इस पेड़ से, यह पता लगाने की कोशिश करें कि शाखा का कौन सा हिस्सा ऐसा दिखता है जैसे इसे छंटनी की जा सकती है।

इस पद्धति का लाभ यह है कि आप इसे प्रति मॉड्यूल के आधार पर कर सकते हैं, इसलिए जब आप टूटे हुए कोड आधार प्राप्त कर लेते हैं, तो बिना समय के बड़ी अवधि के बिना अपने पास से गुजरते रहना आसान है।


3

यदि आप लिनक्स पर हैं, तो आप callgrindएक सी / सी ++ प्रोग्राम विश्लेषण उपकरण देख सकते हैं valgrindजो सूट का हिस्सा है , जिसमें ऐसे उपकरण भी हैं जो मेमोरी लीक और अन्य मेमोरी त्रुटियों (जो आपको अच्छी तरह से उपयोग करना चाहिए) की जांच करते हैं। यह आपके प्रोग्राम के रनिंग इंस्टेंस का विश्लेषण करता है, और इसके कॉल ग्राफ के बारे में और कॉल ग्राफ पर नोड्स की प्रदर्शन लागत के बारे में डेटा का उत्पादन करता है। यह आमतौर पर प्रदर्शन विश्लेषण के लिए उपयोग किया जाता है, लेकिन यह आपके अनुप्रयोगों के लिए एक कॉल ग्राफ़ भी बनाता है, इसलिए आप देख सकते हैं कि फ़ंक्शन क्या कहते हैं, साथ ही साथ उनके कॉलर्स भी।

यह स्पष्ट रूप से पृष्ठ पर कहीं भी उल्लिखित स्थिर विधियों का पूरक है, और यह केवल पूर्ण अप्रयुक्त वर्गों, विधियों, और कार्यों को समाप्त करने के लिए सहायक होगा - यह अच्छी तरह से उन तरीकों के अंदर मृत कोड खोजने में मदद नहीं करता है जिन्हें वास्तव में कहा जाता है।


3

मैंने वास्तव में किसी भी उपकरण का उपयोग नहीं किया है जो ऐसा काम करता है ... लेकिन, जहां तक ​​मैंने सभी उत्तरों में देखा है, किसी ने कभी नहीं कहा कि यह समस्या असुविधाजनक है।

इससे मेरा क्या आशय है? कंप्यूटर पर किसी भी एल्गोरिथ्म द्वारा इस समस्या को हल नहीं किया जा सकता है। यह प्रमेय (कि इस तरह के एक एल्गोरिथ्म मौजूद नहीं है) ट्यूरिंग की हॉल्टिंग समस्या का एक सहसंबंध है।

आपके द्वारा उपयोग किए जाने वाले सभी उपकरण एल्गोरिदम नहीं हैं, लेकिन हेयुरिस्टिक्स (यानी सटीक एल्गोरिदम नहीं)। वे आपको वह सभी कोड नहीं देंगे जो उपयोग नहीं किए गए हैं।


1
मुझे लगता है कि ओपी मुख्य रूप से उन कार्यों को ढूंढना चाहता है जो कहीं से नहीं बुलाए गए हैं, जो निश्चित रूप से असुविधाजनक नहीं है - अधिकांश आधुनिक लिंकर इसे कर सकते हैं! यह सिर्फ उस जानकारी को निकालने की बात है जिसमें कम से कम दर्द और नशे की मात्रा हो।
15:25 बजे j_random_hacker

आप सही हैं, मैंने मुख्य प्रश्न के लिए अंतिम टिप्पणी नहीं देखी। वैसे, कोड में संदर्भित कार्य हो सकते हैं जो वास्तव में उपयोग नहीं किए जाते हैं। इस तरह की चीजों का पता नहीं चल सकता है।
geekazoid

2

एक तरीका डिबगर का उपयोग करना है और संकलन के दौरान अप्रयुक्त मशीन कोड को समाप्त करने की संकलक सुविधा है।

एक बार कुछ मशीन कोड समाप्त हो जाने के बाद डिबगर आपको स्रोत कोड के अनुरूप लाइन पर एक ब्रेकपोजेंट नहीं डालने देगा। इसलिए आप हर जगह ब्रेकपॉइंट लगाते हैं और प्रोग्राम शुरू करते हैं और ब्रेकपॉइंट्स का निरीक्षण करते हैं - जो "इस स्रोत के लिए कोई कोड लोड नहीं है" राज्य कोड को समाप्त करने के लिए अनुरूप है - या तो उस कोड को कभी भी कॉल नहीं किया जाता है या इसे इनलाइन किया गया है और आपको कुछ न्यूनतम प्रदर्शन करना होगा उन दोनों में से किसका पता लगाने के लिए विश्लेषण।

कम से कम यह है कि यह विज़ुअल स्टूडियो में कैसे काम करता है और मुझे लगता है कि अन्य टूलसेट भी ऐसा कर सकते हैं।

यह बहुत काम है, लेकिन मैं सभी कोड का मैन्युअल रूप से विश्लेषण करने की तुलना में तेजी से अनुमान लगाता हूं।


4
मुझे लगता है कि ओपी का सवाल यह है कि स्रोत कोड का एक छोटा, अधिक प्रबंधनीय सबसेट कैसे पाया जाए, इतना नहीं कि यह सुनिश्चित करना कि संकलित बाइनरी कुशल है।
j_random_hacker

@j_random_hacker मैंने इसे हालांकि दे दिया - और कोड को समाप्त कर देता है और मूल स्रोत कोड पर वापस ट्रैकिंग के लिए भी उपयोग किया जा सकता है।
शार्पूथ

क्या आपके पास इसे प्राप्त करने के लिए दृश्य स्टूडियो पर कुछ विशिष्ट संकलक झंडे हैं? और क्या यह केवल रिलीज़ मोड में काम करता है या यह डिबग में भी काम करेगा?
नवीन

उन पंक्तियों के बारे में जो संकलक द्वारा उपयोग की जाती हैं लेकिन अनुकूलित-आउट हैं?
इटमार काट्ज

@ नवीन: विजुअल C ++ 9 में आपको ऑप्टिमाइज़ेशन चालू करना होगा और उपयोग करना होगा / OPT: ICF
sharptooth

2

CppD निर्भर एक वाणिज्यिक उपकरण है जो अप्रयुक्त प्रकार, विधियों और क्षेत्रों का पता लगा सकता है, और बहुत कुछ कर सकता है। यह विंडोज और लिनक्स के लिए उपलब्ध है (लेकिन वर्तमान में 64-बिट समर्थन नहीं है), और 2 सप्ताह के परीक्षण के साथ आता है।

डिस्क्लेमर: मैं वहां काम नहीं करता, लेकिन मेरे पास इस टूल का लाइसेंस है (साथ ही ND निर्भर है , जो .NET कोड के लिए अधिक शक्तिशाली विकल्प है)।

जो लोग जिज्ञासु हैं, उनके लिए CQLINQ में लिखे गए मृत तरीकों का पता लगाने के लिए एक उदाहरण अंतर्निहित (अनुकूलन योग्य) नियम है :

// <Name>Potentially dead Methods</Name>
warnif count > 0
// Filter procedure for methods that should'nt be considered as dead
let canMethodBeConsideredAsDeadProc = new Func<IMethod, bool>(
    m => !m.IsPublic &&       // Public methods might be used by client applications of your Projects.
         !m.IsEntryPoint &&            // Main() method is not used by-design.
         !m.IsClassConstructor &&      
         !m.IsVirtual &&               // Only check for non virtual method that are not seen as used in IL.
         !(m.IsConstructor &&          // Don't take account of protected ctor that might be call by a derived ctors.
           m.IsProtected) &&
         !m.IsGeneratedByCompiler
)

// Get methods unused
let methodsUnused = 
   from m in JustMyCode.Methods where 
   m.NbMethodsCallingMe == 0 && 
   canMethodBeConsideredAsDeadProc(m)
   select m

// Dead methods = methods used only by unused methods (recursive)
let deadMethodsMetric = methodsUnused.FillIterative(
   methods => // Unique loop, just to let a chance to build the hashset.
              from o in new[] { new object() }
              // Use a hashet to make Intersect calls much faster!
              let hashset = methods.ToHashSet()
              from m in codeBase.Application.Methods.UsedByAny(methods).Except(methods)
              where canMethodBeConsideredAsDeadProc(m) &&
                    // Select methods called only by methods already considered as dead
                    hashset.Intersect(m.MethodsCallingMe).Count() == m.NbMethodsCallingMe
              select m)

from m in JustMyCode.Methods.Intersect(deadMethodsMetric.DefinitionDomain)
select new { m, m.MethodsCallingMe, depth = deadMethodsMetric[m] }

अद्यतन: लिनक्स के लिए 64-बिट समर्थन संस्करण 3.1 में जोड़ा गया है।
रोमन बोइको

1

यह आपके एप्लिकेशन को बनाने के लिए आपके द्वारा उपयोग किए जाने वाले प्लेटफ़ॉर्म पर निर्भर करता है।

उदाहरण के लिए, यदि आप Visual Studio का उपयोग करते हैं, तो आप .NET ANTS Profiler जैसे टूल का उपयोग कर सकते हैं जो आपके कोड को पार्स और प्रोफाइल करने में सक्षम है। इस तरह, आपको जल्दी से पता होना चाहिए कि आपके कोड का कौन सा हिस्सा वास्तव में उपयोग किया गया है। ग्रहण में समतुल्य प्लगइन्स भी हैं।

अन्यथा, यदि आपको यह जानने की आवश्यकता है कि आपके एप्लिकेशन का कौन सा फ़ंक्शन वास्तव में आपके अंतिम उपयोगकर्ता द्वारा उपयोग किया जाता है, और यदि आप अपना एप्लिकेशन आसानी से जारी कर सकते हैं, तो आप ऑडिट के लिए लॉग फ़ाइल का उपयोग कर सकते हैं।

प्रत्येक मुख्य फ़ंक्शन के लिए, आप इसके उपयोग का पता लगा सकते हैं, और कुछ दिनों / सप्ताह के बाद बस उस लॉग फ़ाइल को प्राप्त कर सकते हैं, और उस पर एक नज़र डाल सकते हैं।


1
.net ANTS प्रोफाइलर ऐसा लगता है कि यह C # के लिए है - क्या आपको यकीन है कि यह C ++ के लिए भी काम करता है?
j_random_hacker

@j_random_hacker: जब तक मुझे पता है, यह प्रबंधित कोड के साथ काम करता है। तो .net ANTS निश्चित रूप से 'मानक' C ++ कोड (यानी gcc के साथ संकलित ...) का विश्लेषण करने में सक्षम नहीं होगा।
AUS

0

मुझे नहीं लगता कि यह अपने आप हो सकता है।

कोड कवरेज टूल के साथ भी, आपको चलाने के लिए पर्याप्त इनपुट डेटा प्रदान करना होगा।

बहुत जटिल और उच्च मूल्य वाले स्थैतिक विश्लेषण उपकरण हो सकते हैं जैसे कि Coverity या LLVM कंपाइलर से मदद मिल सकती है।

लेकिन मुझे यकीन नहीं है और मैं मैनुअल कोड की समीक्षा करना पसंद करूंगा।

UPDATED

खैर .. केवल अप्रयुक्त चर को हटाना, अप्रयुक्त कार्य हालांकि मुश्किल नहीं है।

UPDATED

अन्य उत्तरों और टिप्पणियों को पढ़ने के बाद, मैं अधिक दृढ़ता से आश्वस्त हूं कि यह नहीं किया जा सकता है।

आपको कोड को सार्थक कोड कवरेज मापने के लिए जानना होगा, और यदि आप जानते हैं कि बहुत मैनुअल संपादन तैयार / रनिंग / कवरेज कवरेज परिणामों की तुलना में तेज़ होगा।


2
आपके उत्तर का शब्द भ्रामक है, LLVM के बारे में कुछ भी हास्यास्पद नहीं है ... यह मुफ़्त है!
मैथ्यू एम।

मैनुअल एडिटिंग आपको रन टाइम चर के साथ मदद नहीं करेगा जो आपके कार्यक्रम में गर्त तर्क शाखाओं को पास करता है। क्या होगा यदि आपका कोड कभी भी एक निश्चित मानदंड को पूरा नहीं कर रहा है और इसलिए हमेशा उसी रास्ते पर चल रहा है?
कार्लोस वी।

0

मेरे एक मित्र ने मुझसे आज यह सवाल पूछा, और मैंने कुछ होनहार क्लैंग घटनाक्रम, जैसे ASTMatcher s और स्टेटिक एनालाइज़र को देखा। को देखा, जिसमें मृत कोड सेक्शन को निर्धारित करने के लिए संकलन के दौरान -ऑन में पर्याप्त दृश्यता हो सकती है, लेकिन तब मैं यह पाया:

https://blog.flameeyes.eu/2008/01/today-how-to-identify-unused-exported-functions-and-variables

यह बहुत कुछ जीसीसी झंडे का उपयोग करने का एक पूरा विवरण है जो प्रतीत होता है कि अप्रतिबंधित प्रतीकों की पहचान करने के उद्देश्य से बनाया गया है!


0

यदि किसी फ़ंक्शन को बुलाया जाएगा की सामान्य समस्या एनपी-पूर्ण है। आप पहले से सामान्य तरीके से नहीं जान सकते हैं, अगर कुछ फ़ंक्शन को बुलाया जाएगा जैसा कि आपको पता नहीं होगा कि क्या ट्यूरिंग मशीन कभी बंद हो जाएगी। यदि आपके द्वारा लिखे गए फ़ंक्शन में मुख्य () से जाने वाले कुछ पथ (स्टेटिक) हैं, तो आप प्राप्त कर सकते हैं, लेकिन यह आपको कभी नहीं बुलाया जाएगा।


-3

अगर आप g ++ का उपयोग कर रहे हैं तो आप इस ध्वज का उपयोग कर सकते हैं -व्यूज्ड

प्रलेखन के अनुसार:

Warn whenever a variable is unused aside from its declaration, whenever a function is declared static but never defined, whenever a label is declared but not used, and whenever a statement computes a result that is explicitly not used.

http://docs.freebsd.org/info/gcc/gcc.info.Warning_Options.html

संपादित करें: यहां अन्य उपयोगी ध्वज है-दस्तावेजीकरण के अनुसार विश्वसनीय-कोड:

This option is intended to warn when the compiler detects that at least a whole line of source code will never be executed, because some condition is never satisfied or because it is after a procedure that never returns.

6
यह सटीक जानकारी पहले से ही वर्तमान में टॉप-रेटेड उत्तर में उल्लिखित है। अनावश्यक नकल से बचने के लिए कृपया मौजूदा उत्तर पढ़ें।
j_random_hacker

1
अब आप अपने सहकर्मी दबाव बिल्ला कमा सकते हैं!
एंड्रयू ग्रिम
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.