Недосяжний код

частина програмного коду, яка за жодних умов не може бути виконаною

У програмуванні та теорії компіляторів, недося́жним ко́дом називають частину коду програми, яка за жодних умов не може бути виконаною, оскільки є недосяжною в графі потоку управління[1][2].

Недосяжний код часто вважають одним із типів мертвого коду, така термінологія зазвичай застосовується при розгляді сирцевого коду програми[3][4]. Однак у теорії компіляторів, ці поняття ніяк не пов'язані, мертвим кодом там називають тільки досяжний код, який не впливає на вивід програми[1][2][5].

Основні недоліки наявності в програмі недосяжного коду:

  • займає зайву пам'ять;
  • є причиною зайвого кешування інструкцій у кеші інструкцій процесора, яке також знижує локальність даних;
  • ускладнює підтримку застосунків — час і сили можуть витрачатися на підтримку і документування частини коду, яка є недосяжною, а отже ніколи не виконується.

Причини виникнення ред.

Існування недосяжного коду обумовлюють різні фактори, наприклад:

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

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

Приклад ред.

Розглянемо наступний приклад на мові Сі:

 int foo(int x, int y)
 {
  return x + y;
  int z = x*y; /* Недостижимый код */
 }

Операція int z = x*y є недосяжним кодом, оскільки перед нею виконується вихід з процедури (операції, що стоять після повернення з процедури можуть і не бути недосяжним кодом, наприклад, якщо на мітку, розташовану після повернення посилається оператор goto).

Аналіз ред.

Пошук недосяжного коду в сирцевому коді можна провести за допомогою статичного аналізу коду[3][4]. За використання оптимізувального компілятора, виявити і видалити недосяжний код здатна оптимізація видалення недосяжного коду, яка знаходить у графі потоку керування недосяжні вузли і видаляє їх[6]. Простий аналіз цього графа на наявність недосяжних вузлів часто буває реалізованим у компіляторі у вигляді окремої функції, так званого прибиральника, яка викликається зразу після перетворень, здатних змінювати граф потоку керування[7].

Код може ставати недосяжним унаслідок виконання компілятором інших перетворень над проміжним поданням[en], наприклад оптимізації усунення спільних підвиразів.

На практиці, складність реалізованого аналізу істотно впливає на кількість виявленого недосяжного коду. Наприклад, після згортання констант[en] і простого аналізу потоку керування можна виявити, що код усередині оператора if у такому прикладі є недосяжним:

 int foo(void)
 {
  int n = 2 + 1;
  if (n > 4)
  {
   printf("%d", n); /* Недостижимый код */
  }
 }

Однак, для того щоб виявити недосяжний код у наступному прикладі, слід застосувати значно складніший алгоритм аналізу:

 int foo(void)
 {
  double x = sqrt(2);
  if (x > 4)
  {
   printf("%lf", x); /* Недостижимый код */
  }
 }

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

Див. також ред.

Примітки ред.

  1. а б Engineering a Compiler — С. 544.
  2. а б Debray, S. K., Evans, W., Muth, R., and De Sutter, B. 2000. Compiler techniques for code compaction [Архівовано 22 травня 2003 у Wayback Machine.]. ACM Trans. Program. Lang. Syst. 22, 2 (Mar. 2000), 378—415. (summary)
  3. а б Dead code detection and removal. Aivosto. Архів оригіналу за 5 серпня 2012. Процитовано 12 липня 2012.
  4. а б Compares some free alternatives to DCD (Dead Code Detector). Java.net. Архів оригіналу за 23 вересня 2012. Процитовано 12 липня 2012.
  5. Компиляторы — принципы, технологии, инструменты — С. 669 (недостижимый код), 713 (мёртвый код).
  6. Engineering a Compiler — С. 550.
  7. А. Ю. Дроздов, А. М. Степаненков. Управляемые пакеты оптимизаций. В Информационные технологии и вычислительные системы, 2004, № 3 (текст [Архівовано 2016-03-04 у Wayback Machine.])

Література ред.

  • Cooper and Torczon. Engineering a Compiler. — Morgan Kaufmann, 2011. — С. 544-550, 593. — ISBN 978-0-12-088478-0.
  • Альфред Ахо, Моника Лам, Рави Сети, Джеффри Ульман. Компиляторы: принципы, технологии и инструментарий = Compilers: Principles, Techniques, and Tools. — 2-е издание. — М.: «Вильямс», 2008. — 1184 с. — 1500 экз. — ISBN 978-5-8459-1349-4.
  • Muchnick, Steven S. Advanced Compiler Design and Implementation. — Morgan Kaufmann Publishers, 1997. — С. 580-582. — ISBN 1-55860-320-4.