2013-04-05 3 views
7

Существует много раз, когда, когда я отлаживаю или повторно использую код, файл начинает получать строки, которые ничего не делают, хотя они, возможно, что-то сделали в какой-то момент.Удаление ненужных строк из файла C++

Вещи, подобные векторам, и заполняются, а затем не используются, классы/структуры, которые определены, но никогда не используются, и функции, объявленные, но никогда не используемые.

Я понимаю, что во многих случаях некоторые из этих вещей не являются излишними, поскольку они могут быть видны из других файлов, но в моем случае нет других файлов, только посторонний код в моем файле.

Хотя я понимаю, что технически говоря, вызывая push_back что-то делает, и поэтому вектор не используется сам по себе, в моем случае его результат не используется.

So: Есть ли способ сделать это, используя компилятор (clang, gcc, VS и т. Д.) Или внешний инструмент?

Пример:

#include<vector> 
using namespace std; 
void test() { 
    vector<int> a; 
    a.push_back(1); 
} 
int main() { 
    test(); 
    return 0; 
} 

должны стать: int main(){return 0};

ответ

3

Наш DMS Software Reengineering Toolkit с его интерфейсом C++ 11 можно использовать для этого; он в настоящее время не делает этого с полки. DMS предназначен для создания пользовательских инструментов для произвольных исходных языков и содержит полные анализаторы, преобразователи имен и различные анализаторы потоков для поддержки анализа, а также возможность применения преобразований источника к источнику кода на основе результатов анализа.

В общем, вы хотите, чтобы статический анализ определял, используется ли каждое вычисление (результат, может быть несколько, считать только «x ++») или нет. Для каждого неиспользованного вычисления, по сути, вы хотите удалить неиспользуемые вычисления и повторить анализ.По соображениям эффективности вы хотите провести анализ, который определяет все (точки) использования результатов (результатов) только один раз; это, по сути, анализ потока данных. Когда набор результатов вычисления будет пустым, этот результат вычисления можно удалить (обратите внимание, что удаление значения «x ++» может оставить «x ++», потому что приращение по-прежнему необходимо!) И наборы наборов вычислений, от которых это зависит можно отрегулировать для удаления ссылок с удаленных, что может привести к большему количеству абзацев.

Для этого анализа на любом языке вы должны отслеживать результаты. Для C (и C++) это может быть довольно уродливым; существует «очевидное» использование, когда результат вычисления используется в выражении и где ему присваивается локальная/глобальная переменная (которая используется где-то в другом месте), и есть косвенные назначения через указатели, обновления полей объекта, посредством произвольных отбрасываний и т. д. Чтобы узнать об этих эффектах, инструмент анализа мертвого кода должен иметь возможность прочитать всю программную систему и вычислить потоки данных через нее.

Чтобы быть в безопасности, вы хотите, чтобы этот анализ был консервативным, например, если инструмент не имеет доказательств того, что результат не используется, тогда он должен предположить, что результат используется; вам часто приходится делать это с помощью указателей (или индексов массива, которые просто маскируют указатели), потому что в общем случае вы не можете точно определить, где указатель «указывает». Очевидно, что можно создать «безопасный» инструмент, предполагая, что все результаты будут использованы: -} Вы также получите иногда очень консервативные, но необходимые предположения для библиотечных процедур, для которых у вас нет источника. В этом случае полезно иметь набор предварительно вычисленных итогов побочных эффектов библиотеки (например, «strcmp» не имеет, «sprintf» перезаписывает определенный операнд, «push_back» изменяет его объект ...). Поскольку библиотеки могут быть довольно большими, этот список может быть довольно большим.

DMS в целом может анализировать и всю базу исходного кода, создавать таблицы символов (поэтому он знает, какие идентификаторы являются локальными/глобальными и их точный тип), осуществлять контроль и анализ локального потока данных, создавать локальные сводки «побочные эффекты» для каждой функции , построить график вызовов и глобальные побочные эффекты, а также сделать глобальный анализ точек, предоставляя эту «используемую для вычисления» информацию с соответствующим консерватизмом.

DMS был использован для выполнения вычислений на C-кодовых системах из 26 миллионов строк кода (и да, это действительно большой расчет, для запуска требуется 100Gb VM). Мы не реализовали часть устранения мертвого кода (у проекта была другая цель), но это просто, как только у вас есть эти данные. DMS выполнила исключение мертвого кода на больших Java-кодах с более консервативным анализом (например, «без использования упоминаний идентификатора», что означает, что присвоения идентификатора мертвы), что вызывает удивительный объем удаления кода во многих реальных кодах.

CMS-анализатор DMS в настоящее время строит таблицы символов и может выполнять анализ потока управления для C++ 98, поскольку C++ 11 находится под рукой. Нам все еще нужен локальный анализ потока данных, что является некоторым усилием, но глобальный анализ уже существует в DMS и доступен для использования для этого эффекта. («Без использования идентификатора» легко получить из данных таблицы символов, если вы не против более консервативного анализа).

На практике вы не хотите, чтобы инструмент просто молчал; некоторые могут фактически быть вычислениями, которые вы хотите сохранить в любом случае. Что делает инструмент Java, это дает два результата: список мертвых вычислений, которые вы можете проверить, чтобы решить, верите ли вы, и версию исходного кода с удаленным кодом. Если вы считаете отчет мертвого кода, вы сохраняете версию с удаленным кодом; если вы видите «мертвое» вычисление, которое, по вашему мнению, не должно быть мертвым, вы изменяете код, чтобы он не был мертвым, и снова запустите инструмент. С большой базой кода можно попробовать проверить сам отчет о мертвом коде; как «вы» знаете, если какой-либо достойный мертвый код не ценится «кем-то другим» в вашей команде ?. (Управление версиями может быть использовано для восстановления, если вы goof!)

Действительно сложная проблема, с которой мы не справляемся (и нигде не знаю), является «мертвым кодом» при наличии условной компиляции.(Java не имеет этой проблемы, C имеет это в пиках, а на C++ - гораздо меньше). Это может быть действительно неприятно. Представьте условное выражение, в котором рука имеет определенные побочные эффекты, а другая рука имеет разные побочные эффекты, или другой случай, в котором один из них интерпретируется компилятором GCC C++, а другой рычаг интерпретируется MS, а компиляторы не согласны с тем, что делают конструкции (да, компиляторы C++ не согласны в темных углах). В лучшем случае мы можем быть очень консервативными.

CLANG имеет некоторую способность проводить анализ потока; и некоторая способность делать преобразования источника, поэтому его можно было бы принудить к этому. Я не знаю, может ли он провести глобальный анализ потоков/точек. Кажется, что он имеет предвзятость к единым единицам компиляции, поскольку его основное использование составляет единую единицу компиляции.

+0

[Интересный разговор] (http://www.youtube.com/watch?v=C-_dw9iEzhA), а также – soandos

1

Чтобы поймать неиспользуемые переменные, вы можете включить -Wunused флаг на GCC компилятора. Это предупредит вас о неиспользуемых параметрах, переменных и вычисленных значениях во время компиляции. Я обнаружил, что использование флагов -Wall -Wextra и -Werror гарантирует, что компилятор поймает некоторые из проблем, которые вы описываете. Более подробную информацию можно найти здесь: http://gcc.gnu.org/onlinedocs/gcc/Warning-Options.html

Что касается обнаружения неиспользуемых классов, один вариант заключается в использовании IDE, скажем, как Eclipse, и использовать функцию «Найти References» для поиска мест, где этот класс/объект может быть используемый.

+0

Это намного проще, чем то, что я пытаюсь сделать. – soandos

+0

Если я правильно понял, он не ищет неиспользуемые переменные, но и для изменений в переменных, которые никогда не читаются (т. Е. Используется переменная, вероятно, читаются/записываются многие раз, но в конце есть цепочка записей, которая никогда не читается, и он хочет исключить эти записи) –

+0

@ DavidRodríguez-dribeas, см. пример – soandos

1

Короткий ответ - «нет». Невозможно сказать статическим анализом кода клиента, что метод push_back этого вектора не имеет каких-либо важных побочных эффектов. Для всех инструментов анализа известно, что он где-то пишет базу данных и управляет торговлей акциями.

+0

Является ли это проблемой, которая может быть решена путем аннотирования функций? – soandos

+0

@soandos Что я не знаю. Я просто указываю, что для этого требуется гораздо более глубокий анализ, чем в типичной среде IDE. И я бы не затаил дыхание. – djechlin

+0

+1. Обычно я предлагаю CppCheck здесь. Но факт в том, что в приведенном выше примере CppCheck не на что жаловаться. :-( – TobiMcNamobi

0

Я бы рекомендовал использовать программное обеспечение для управления версиями - SVN, Git, Mercurial, Perforce, ... - чтобы после отладки вы могли использовать этот инструмент управления версиями для поиска и удаления остатков отладки. Это упрощает работу вашего кода.

Кроме того, этот тип тестового кода, как правило, имеет небольшое покрытие для тестирования, поэтому, если у вас есть модульное тестирование, они должны отображаться как не охваченный код.

Тогда есть инструменты, которые явно ищут этот материал - Lint, Coverity и так далее. Большинство из них являются коммерческими. Также попробуйте использовать -O3 на GCC, компилятор может распознать более фактически неиспользуемые переменные таким образом, поскольку он будет более агрессивно внедрять и исключать код.

Смежные вопросы