Як я можу знати, які частини в коді ніколи не використовуються?


312

У мене є застарілий код C ++, з якого я повинен видалити невикористаний код. Проблема в тому, що база коду велика.

Як я можу дізнатися, який код ніколи не називається / ніколи не використовується?


4
Я думаю, що мова запиту коду дасть вам кращий огляд вашого проекту в цілому. Я не впевнений у світі c ++, але, здається, є cppdepend.com (це не безкоштовно), який виглядає досить пристойно. Можливо, щось подібне може бути доступне безкоштовно. Інша справа, що перед тим, як робити будь-який вид рефакторингу, розумним, що потрібно зробити, було б тестування одиниць, якщо у вас зараз немає. За допомогою тестування одиниць, що ви можете зробити, - це за допомогою інструментів для покриття коду профайл вашого коду, який в самому собі допоможе видалити мертвий код, якщо ви не можете покрити цей код.
Бісванат

3
Ознайомтесь з посиланням тут: en.wikipedia.org/wiki/Unreachable_code
Мартін Йорк

6
Я знаходжу подібну тему. stackoverflow.com/questions/229069 / ...
Ummagumma

3
Так, однією із найсмішніших речей C ++ є те, що видалення "невикористаних" функцій все ще може змінити результат програми.
MSalters

1
@MSalters: Це цікаво ... Для цього нам слід було б говорити про те, яка функція в наборі перевантаження обрана для даного дзвінка, правильно? Наскільки мені відомо, якщо є дві функції, і названі f(), і виклик f()однозначно вирішується на 1-ю, тоді неможливо зробити цей виклик вирішенням другої, просто додавши 3-й функцію з назвою f()- "найгірше, що ви можете зробити ", додавши, що третя функція полягає в тому, щоб виклик став неоднозначним і тому не дозволяв програмі компілювати. Дуже хотілося б (= жахнувся) побачити контрприклад.
j_random_hacker

Відповіді:


197

Існує два різновиди невикористаного коду:

  • локальна, тобто в деяких функціях деякі шляхи або змінні не використовуються (або використовуються, але не мають сенсу, як написані, але ніколи не читаються)
  • глобальний: функції, які ніколи не викликаються, глобальні об'єкти, до яких ніколи не звертаються

Для першого виду хороший компілятор може допомогти:

  • -Wunused(GCC, Clang ) слід попередити про невикористані змінні, невикористаний аналізатор Clang навіть збільшується, щоб попереджати про змінні, які ніколи не читаються (хоча вони і використовуються).
  • -Wunreachable-code(старіший GCC, видалений у 2010 році ) повинен попереджати про локальні блоки, до яких ніколи не можна отримати доступ (це трапляється з ранньою віддачею або умовами, які завжди оцінюються як справжні)
  • не існує жодної опції, про яку я знаю попереджати про невикористані catchблоки, оскільки компілятор, як правило, не може довести, що жоден виняток не буде викинутий.

Для другого роду це набагато складніше. Статично він вимагає цілого аналізу програми, і хоча оптимізація часу зв'язку може фактично видалити мертвий код, на практиці програма настільки сильно трансформувалася під час її виконання, що неможливо передати змістовну інформацію користувачеві.

Тому існує два підходи:

  • Теоретичним є використання статичного аналізатора. Програмне забезпечення, яке вивчить весь код одразу докладно та знайде всі шляхи потоку. На практиці я не знаю жодної, яка б тут працювала.
  • Прагматичним є використання евристики: використовувати інструмент покриття коду (у ланцюзі GNU це gcov. Зауважте, що під час компіляції для правильної роботи повинні бути передані конкретні прапори). Ви запускаєте інструмент покриття коду з хорошим набором різноманітних входів (ваші одиничні тести або нерегресійні тести), мертвий код обов'язково знаходиться в межах недосягнутого коду ... і ви можете почати звідси.

Якщо ви надзвичайно зацікавлені в цій темі і маєте час і схильність реально розробити інструмент самостійно, я б запропонував використовувати бібліотеки Кланг для створення такого інструменту.

  1. Використовуйте бібліотеку Clang, щоб отримати AST (абстрактне синтаксичне дерево)
  2. Виконайте аналіз розмітки від точок входу і далі

Оскільки Кланг розбере код для вас і виконає вирішення перевантаження, вам не доведеться мати справу з правилами мов C ++, і ви зможете зосередитись на проблемі.

Однак такий метод не може визначити невикористані віртуальні зміни, оскільки їх можна викликати стороннім кодом, про який ви не можете міркувати.


7
Дуже приємно, +1. Мені подобається, що ви розрізняєте код, який можна статично визначити, що ніколи не запускатись ні за яких обставин, і код, який не працює в певному циклі, але потенційно міг би. Перший є важливим, на мій погляд, і, як ви кажете, аналіз доступності з використанням AST всієї програми - це спосіб її отримати. (Забороняється foo()позначати як "закликане", коли воно з'являється лише в, if (0) { foo(); }було б бонусом, але вимагає додаткових
розумних дій

@j_random_hacker: можливо, що використовувати CFG (Control-Flow Graph) було б краще зараз, коли я думаю про це (завдяки вашому прикладу). Я знаю, що Кланг прагне зауважити про тавтологічні порівняння на зразок того, про яке ви згадали, і таким чином, використовуючи CFG, ми могли, можливо, виявити мертвий код на початку.
Матьє М.

@Matthieu: Так, можливо, CFG - це те, про що я також маю на увазі, замість AST :) Що я маю на увазі: це диграф, в якому вершини є функціями, і є край від функції x до функції y, коли x можливо може викликати y. (І з важливою властивістю, що всі перевантажені функції представлені різними вершинами - звучить так, як Кланг робить це для вас, феу!)
j_random_hacker

1
@j_random_hacker: насправді CFG є складнішим, ніж простий диграф, оскільки він представляє весь код, який повинен виконуватися в блоках із посиланнями від одного блоку до іншого на основі умовних висловлювань. Основна перевага полягає в тому, що він, природно, підходить для коду обрізки, який статично може бути визначений мертвим (він створює недоступні блоки, які можна ідентифікувати), тому було б краще використовувати CFG, ніж AST, щоб створити диграф говоримо про ... я думаю :)
Матьє М.

1
@j_random_hacker: насправді AST робить Кланг, він робить все явним (або майже ...), оскільки він призначений для роботи з кодом, а не просто для його складання. Наразі існує дискусія, оскільки, мабуть, існує проблема зі списками ініціалізаторів, де таке неявне перетворення не відображається в AST, але я думаю, це буде виправлено.
Матьє М.

35

Що стосується невикористаних цілих функцій (та невикористаних глобальних змінних), GCC може фактично виконати більшу частину роботи за вас за умови, що ви використовуєте GCC та GNU ld.

Складаючи джерело, використовуйте, -ffunction-sectionsа -fdata-sectionsпотім при посиланні -Wl,--gc-sections,--print-gc-sections. Тепер лінкер перелічить всі функції, які можна було б видалити, оскільки вони ніколи не викликалися, та всі глобальні кулі, на які ніколи не було посилань.

(Звичайно, ви також можете пропустити --print-gc-sectionsчастину і дозволити лінкеру мовчки видаляти функції, але зберігати їх у джерелі.)

Примітка: це знайде лише невикористані повноцінні функції, воно нічого не зробить з мертвим кодом у функціях. Функції, викликані з мертвого коду, в живих функціях також будуть зберігатися навколо.

Деякі особливості C ++ також спричинять проблеми, зокрема:

  • Віртуальні функції. Не знаючи, які підкласи існують, а які насправді інстанціюються під час виконання, ви не можете знати, які віртуальні функції потрібно існувати в кінцевій програмі. У лінкера недостатньо інформації про це, тому доведеться тримати їх навколо.
  • Глобали з конструкторами та їх конструктори. Взагалі, лінкер не може знати, що конструктор для глобального не має побічних ефектів, тому він повинен запустити його. Очевидно, це означає, що і сам глобал також повинен зберігатися.

В обох випадках все, що використовується віртуальною функцією або конструктором глобальної змінної, також має зберігатися навколо.

Додатковим застереженням є те, що якщо ви створюєте спільну бібліотеку, налаштування за замовчуванням у GCC експортують кожну функцію в спільній бібліотеці, приводячи її до "використання", що стосується посилання. Щоб виправити, що вам потрібно встановити за замовчуванням приховування символів замість експорту (використовуючи напр. -fvisibility=hidden), А потім чітко вибрати експортовані функції, які потрібно експортувати.


Чудові практичні поради. Просто отримання списку функцій, які, як відомо, ніде не використовуються (навіть якщо, як ви говорите, цей список не є повним), ви отримаєте багато низько висячих фруктів.
j_random_hacker

Я не думаю, що жодне з цього не працює для необґрунтованих шаблонів .
Якуб Клінковський

25

Добре, якщо ви використовуєте g ++, ви можете використовувати цей прапор -Wunused

Відповідно до документації:

Попереджайте, коли змінна не використовується, окрім її декларації, щоразу, коли функція оголошується статичною, але ніколи не визначається, коли мітка оголошується, але не використовується, і коли вираз обчислює результат, який явно не використовується.

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

Редагувати : Ось інший корисний прапор -Wunreachable-code Відповідно до документації:

Цей параметр призначений для попередження, коли компілятор виявить, що принаймні цілий рядок вихідного коду ніколи не буде виконаний, оскільки якась умова ніколи не виконується або тому, що це після процедури, яка ніколи не повертається.

Оновлення : я знайшов аналогічну тему Виявлення мертвого коду у застарілому проекті C / C ++


4
Це не зачепить заголовки тих функцій прототипу, які ніколи не викликаються. Або методи загальнодоступного класу, які не викликаються. Він може перевірити лише, чи використовуються змінні локального діапазону в межах цієї області.
Фальмарі

@Falmarri Я ніколи не використовував цей прапор. Я намагаюся зрозуміти, які саме мертві коди я можу знайти.
UmmaGumma

-Wunusedпопереджає про змінні, які оголошуються (або оголошуються та визначаються за один раз), але насправді ніколи не використовуються. До речі, дуже дратує з охопленням охоронців: p Існує експериментальна реалізація в Clang, щоб він також попереджав про енергонезалежних змінних, які записуються, але ніколи не читаються (Тед Кременек). -Wunreachable-codeпопереджає про код у межах функції, яку неможливо досягти, вона може бути кодом, розташованим після a, throwабо returnзаявою чи кодом у гілці, яка ніколи не приймається (що відбувається у разі тавтологічних порівнянь), наприклад.
Матьє М.

18

Я думаю, ви шукаєте інструмент для покриття коду . Інструмент покриття коду проаналізує ваш код під час його запуску, і він дозволить вам знати, які рядки коду виконувались і скільки разів, а також які не були.

Ви можете спробувати надати шанс цього інструменту покриття відкритого коду: TestCocoon - інструмент покриття коду для C / C ++ та C #.


7
Ключовим тут є "як він працює" - якщо ваші вхідні дані не здійснюють деякий шлях коду, цей шлях не буде розпізнаний як використаний, чи не так?
гострий зуб

1
Це правильно. Без запуску коду неможливо дізнатися, до яких рядків не доходить. Цікаво, як важко буде налаштувати кілька тестів для імітації декількох нормальних пробігів.
Карлос V

1
@drhishch Я думаю, що більшість таких невикористаних кодів повинні знаходити лінкер, а не компілятор.
UmmaGumma

1
@drhirsch Щоправда, компілятор може подбати про деякі недоступні коди, такі як функції, які оголошуються, але не викликаються, і деякі оцінки короткого замикання, а як бути з кодом, який залежить від дії користувача, або запустити змінні часу?
Карлос V

1
@golcarcol Добре, маємо функцію void func()в a.cpp, який використовується в b.cpp. Як компілятор може перевірити, що func () використовується в програмі? Це робота лінкерів.
UmmaGumma

15

Справжня відповідь тут така: Ви ніколи не можете точно знати точно.

Принаймні, у нетривіальних випадках ви не можете бути впевнені, що ви все це здобули. Розглянемо наступне зі статті Вікіпедії про недосяжний код :

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функції, або для кожної функції в math.h , або для будь-якої функції з фіксованим входом, домен якої може визначити. Це стає дуже, дуже складним, а складність в основному безмежна. Ви можете продовжувати додавати шари вишуканості у ваш компілятор, але завжди знайдеться спосіб прокрастись у якийсь код, який буде недоступний для будь-якого набору входів.

А потім є набори введення, які просто ніколи не вводяться. Вхід, який би не мав сенсу в реальному житті, або заблокований логікою перевірки в іншому місці. Компілятор не може знати про них.

Кінцевим результатом цього є те, що, хоча згадані інші програмні засоби є надзвичайно корисними, ви ніколи не будете точно знати, що все зловили, якщо потім не вручаєте код вручну. Навіть тоді ви ніколи не будете впевнені, що нічого не пропустили.

Єдине справжнє рішення - IMHO - бути максимально пильним, використовувати автоматику, яка є у вашому розпорядженні, рефактор, де ви можете, і постійно шукати шляхи вдосконалення свого коду. Звичайно, це все-таки добре зробити.


1
Правда і не залишайте мертвий код у! Якщо ви видалите функцію, вбийте мертвий код. Залишаючи його там «про всяк випадок», це просто спричиняє набряк, який (як ви вже обговорювали) згодом важко знайти. Нехай контроль версій робить приховування для вас.
Гонки легкості на орбіті

12

Я сам не користувався цим, але cppcheck , стверджує, що знаходить невикористані функції. Це, мабуть, не вирішить повну проблему, але це може бути початком.


Так, він може знайти локальні невіднесені змінні та функції.
Чугайстер

Так використовуйте cppcheck --enable=unusedFunction --language=c++ .для пошуку цих невикористаних функцій.
Джейсон Харріс

9

Ви можете спробувати використовувати PC-lint / FlexeLint від Gimple Software . Це претендує на

знаходити невикористані макроси, typedef, класи, члени, декларації тощо у всьому проекті

Я використовував його для статичного аналізу і вважав це дуже хорошим, але мушу визнати, що я не використовував його для конкретного пошуку мертвого коду.


5

Мій звичайний підхід до пошуку невикористаних речей - це

  1. переконайтесь, що система збірки правильно обробляє відстеження залежності
  2. налаштуйте другий монітор із повним екраном термінального вікна, виконуючи повторні складання та показуючи перший скріншот виводу. watch "make 2>&1"прагне зробити трюк на Unix.
  3. запустіть операцію пошуку та заміни у всьому дереві джерела, додавши "//?" на початку кожного рядка
  4. виправити першу помилку, позначену компілятором, видаливши "//?" у відповідних рядках.
  5. Повторюйте, поки не залишиться помилок.

Це дещо тривалий процес, але він дає хороші результати.


2
Має заслуги, але дуже трудомісткий. Крім того, ви повинні переконувати одночасно всі перевантаження функції - якщо більше ніж одна застосовна, коментування менш вподобаного може дозволити компіляції досягти успіху, але призвести до неправильної поведінки програми (і неправильної ідеї про те, що функції використовуються).
j_random_hacker

Я лише розв'язую декларації на першому кроці (усі перевантаження), а на наступній ітерації потім бачу, яких визначень не вистачає; таким чином я бачу, які перевантаження фактично використовуються.
Саймон Ріхтер

@Simon: Цікаво, що в коментарі до головного питання MSalters вказує, що навіть наявність / відсутність декларації для функції, яка ніколи не викликається, може вплинути на те, яка з двох інших функцій буде виявлена ​​шляхом вирішення перевантаження. Звичайно, для цього потрібні надзвичайно химерні та надумані установки, тому навряд чи це буде проблемою на практиці.
j_random_hacker

4

Позначте стільки загальнодоступних функцій і змінних як приватні або захищені, не викликаючи помилок компіляції, виконуючи це, намагайтеся також рефакторировать код. Роблячи функції приватними та певною мірою захищеними, ви зменшили область пошуку, оскільки приватні функції можна викликати лише з одного класу (якщо немає дурних макро чи інших хитрощів, щоб обійти обмеження доступу, і якщо це так, я б рекомендував вам знайти нову роботу). Набагато простіше визначити, що вам не потрібна приватна функція, оскільки лише клас, над яким ви зараз працюєте, може викликати цю функцію. Цей спосіб простіший, якщо у вашій кодовій базі є невеликі класи та вони зв'язані слабко. Якщо у вашій кодовій базі немає малих класів або у вас дуже щільне з'єднання, я пропоную їх попередньо очистити.

Далі буде позначати всі публічні функції, що залишилися, і робити графік виклику, щоб з'ясувати взаємозв'язок між класами. З цього дерева спробуйте з’ясувати, яка частина гілки виглядає, як її можна обрізати.

Перевага цього методу полягає в тому, що ви можете робити це на основі модулів, тому легко тримати проходження свого тесту без великого періоду часу, коли у вас зламана база коду.


3

Якщо ви працюєте в Linux, можливо, ви захочете заглянути callgrindінструмент аналізу програм C / C ++, який є частиною valgrindнабору, який також містить інструменти, які перевіряють наявність витоків пам'яті та інших помилок пам'яті (які ви також повинні використовувати). Він аналізує запущений примірник вашої програми та виробляє дані про її графік викликів та про витрати на ефективність вузлів на графіку викликів. Зазвичай він використовується для аналізу продуктивності, але він також створює графік викликів для ваших програм, так що ви можете бачити, як називаються функції, а також їх дзвінки.

Це, очевидно, доповнює статичні методи, згадані в інших місцях на сторінці, і буде корисним лише для усунення повністю невикористаних класів, методів та функцій - це добре не допоможе знайти мертвий код всередині методів, які насправді викликаються.


3

Я справді не використовував жодного інструменту, який би робив таку дію ... Але, наскільки я бачив у всіх відповідях, ніхто ніколи не говорив, що ця проблема є непорушною.

Що я маю на увазі під цим? Ця проблема не може бути вирішена жодним алгоритмом, коли-небудь на комп'ютері. Ця теорема (що такого алгоритму не існує) є наслідком проблеми зупинки Тьюрінга.

Усі інструменти, які ви будете використовувати, - це не алгоритми, а евристика (тобто не точні алгоритми). Вони не дадуть вам точно весь код, який не використовується.


1
Я думаю, що ОП в основному хоче знайти функції, які не викликаються з будь-якого місця, що, звичайно, не є непорушним - більшість сучасних лінкерів можуть це зробити! Це лише питання вилучення цієї інформації з найменшою кількістю болю та зухвалості.
j_random_hacker

Ви маєте рацію, я не бачив останнього коментаря до головного питання. До речі, в коді можуть бути функції, які фактично не використовуються. Такі речі можуть бути не виявлені.
geekazoid

2

Одним із способів є використання налагоджувача та функції компілятора для усунення невикористаного машинного коду під час компіляції.

Після усунення деякого машинного коду відладчик не дозволить вам поставити breakpojnt у відповідний рядок вихідного коду. Таким чином, ви ставите точки прориву скрізь і запускаєте програму та перевіряєте точки прориву - ті, які перебувають у стані "жодного коду не завантажено для цього джерела", відповідають виключеному коду - або цей код ніколи не викликається, або він був накреслений, і ви повинні виконати деякий мінімум аналіз, щоб знайти, хто з цих двох стався.

Принаймні, так це працює у Visual Studio, і я думаю, що інші набори інструментів також можуть це зробити.

Це багато роботи, але я думаю, що швидше, ніж вручну аналізувати весь код.


4
Я думаю, що питання ОП полягає в тому, як знайти менший, більш керований підмножина вихідного коду, не так багато, щоб переконатися, що складений двійковий файл є ефективним.
j_random_hacker

@j_random_hacker Я хоч і дав це - і, виявляється, усунення коду може бути використане навіть для відстеження до початкового вихідного коду.
гострий зуб

чи потрібні вам якісь конкретні прапори компілятора на візуальній студії, щоб досягти цього? і чи працює він лише у режимі випуску чи він також буде працювати у налагодженні?
Naveen

А як щодо рядків, які використовуються, але оптимізовані компілятором?
Ітамар Кац

@Naveen: У Visual C ++ 9 вам слід увімкнути оптимізацію та використовувати / OPT: ICF
shartooth

2

CppDepend - комерційний інструмент, який може виявляти невикористані типи, методи та поля та робити багато іншого. Він доступний для Windows та Linux (але на даний момент не має 64-розрядної підтримки) та проходить 2-тижневу пробну версію.

Відмова: Я не працюю там, але я маю ліцензію на цей інструмент (як і NDepend , яка є більш потужною альтернативою коду .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] }

Оновлення: у версії 3.1 додана 64-розрядна підтримка Linux.
Роман Бойко

1

Це залежить від платформи, яку ви використовуєте для створення своєї програми.

Наприклад, якщо ви використовуєте Visual Studio, ви можете використовувати такий інструмент, як .NET ANTS Profiler, який здатний проаналізувати і профайлювати ваш код. Таким чином, ви повинні швидко знати, яка частина вашого коду фактично використовується. Eclipse також має еквівалентні плагіни.

В іншому випадку, якщо вам потрібно знати, яку функцію вашої програми фактично використовує ваш кінцевий користувач, і якщо ви можете легко випустити свою програму, ви можете використовувати файл журналу для аудиту.

Для кожної основної функції ви можете простежити її використання, а через кілька днів / тиждень просто отримати цей файл журналу та ознайомитися з ним.


1
.net ANTS Profiler виглядає як для C # - ви впевнені, що він працює і для C ++?
j_random_hacker

@j_random_hacker: наскільки я знаю, він працює з керованим кодом. Тож .net ANTS, безумовно, не зможе проаналізувати «стандартний» код C ++ (тобто складений з gcc, ...).
AUS

0

Я не думаю, що це можна зробити автоматично.

Навіть за допомогою інструментів покриття коду вам потрібно забезпечити достатню кількість вхідних даних для запуску.

Може бути дуже складним і дорогоцінним інструментом статичного аналізу, таким як компілятор Coverity або LLVM, може допомогти.

Але я не впевнений, і я вважаю за краще ручний перегляд коду.

ОНОВЛЕНО

Ну .. тільки видалення невикористаних змінних, невикористаних функцій не важко, хоча.

ОНОВЛЕНО

Прочитавши інші відповіді та коментарі, я переконаний, що цього зробити не можна.

Ви повинні знати код, щоб мати змістовну міру покриття коду, і якщо ви знаєте, що багато вручну редагування буде швидше, ніж підготовка / запуск / перегляд результатів покриття.


2
Формулювання вашої відповіді вводить в оману, в LLVM немає нічого цінного ... це безкоштовно!
Матьє М.

ручне редагування не допоможе вам із змінними часу виконання, які проходять через логічні гілки вашої програми. Що робити, якщо ваш код ніколи не відповідає певним критеріям і тому завжди йде за тим самим шляхом?
Карлос V

0

Сьогодні у мене був друг, який задав мені це запитання, і я оглянув деякі перспективні розробки Clang, наприклад, ASTMatcher s та статичний аналізатор, які могли б мати достатню видимість в роботі під час компіляції для визначення розділів мертвого коду, але тоді я знайшов це:

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

Це майже повний опис того, як використовувати декілька прапорів GCC, які, здавалося б, розроблені з метою ідентифікації невизначених символів!


0

Загальна проблема, якщо якась функція буде викликана, - NP-Complete. Ви не можете заздалегідь дізнатися, чи буде викликана якась функція, оскільки ви не знатимете, чи машина колись зупиниться. Ви можете отримати, якщо є якийсь шлях (статично), який йде від main () до функції, яку ви написали, але це не гарантує вас, що коли-небудь буде викликано.


-3

Добре, якщо ви використовуєте g ++, ви можете використовувати цей прапор -Wunused

Відповідно до документації:

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 та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.