Анализ включает директивы для медленных построений единиц перевода [duplicate]

Симон Моурир дал этот пример :

object o = null;
DateTime d = (DateTime)o;  // NullReferenceException

, где unboxing преобразование (литье) из object (или из одного из классов System.ValueType или System.Enum или из типа интерфейса) - тип значения (кроме Nullable<>) сам по себе дает NullReferenceException.

В другом направлении конверсия бокса из a Nullable<>, которая имеет HasValue, равную false , на ссылочный тип, может дать ссылку null, которая затем может привести к NullReferenceException. Классический пример:

DateTime? d = null;
var s = d.ToString();  // OK, no exception (no boxing), returns ""
var t = d.GetType();   // Bang! d is boxed, NullReferenceException

Иногда бокс происходит по-другому. Например, с помощью этого не общего метода расширения:

public static void MyExtension(this object x)
{
  x.ToString();
}

следующий код будет проблематичным:

DateTime? d = null;
d.MyExtension();  // Leads to boxing, NullReferenceException occurs inside the body of the called method, not here.

Эти случаи возникают из-за специальных правил, используемых во время выполнения при боксе Nullable<> экземпляров.

231
задан shoosh 5 March 2009 в 14:43
поделиться

19 ответов

Это не автоматическое, но Doxygen создаст диаграммы зависимостей для # включенных файлов. Вам придется пройти через них визуально, но они могут быть очень полезны для получения изображения того, что использует.

37
ответ дан user 31 August 2018 в 09:44
поделиться
  • 1
    Это отличный способ увидеть цепочки .. видя A - & gt; B - & gt; C - & gt; D и A - & gt; D немедленно обнаруживает избыточность. – Tom 6 March 2009 в 02:36
  • 2
    Как вы сделали диаграммы зависимостей Doxygen? – Maksim Dmitriev 29 July 2014 в 10:07
  • 3

Также проверьте include-what-you-use , который решает подобную проблему.

51
ответ дан Étienne 31 August 2018 в 09:44
поделиться
  • 1
    ИМХО этот ответ нуждается в гораздо большем количестве оборотов, поскольку, как только изломы будут разработаны, инструмент IWYU от Google станет решающим инструментом для этой задачи. – Dan Olson 12 April 2011 в 20:28
  • 2
    sudo apt-get install iwyu – Andrew Wagner 15 October 2015 в 15:21
  • 3
    Кажется замечательным - с двумя cavaets 1) последнее обновление Feb 2106 2) Gogole сами используют его только для C ++, а не C, который запросил OP. – Mawg 7 September 2016 в 06:47
  • 4
    Можете ли вы немного объяснить, как пользователь должен его использовать? README не очень ясен, что содержит вывод скрипта python. – King's jester 10 August 2017 в 08:45
  • 5
    Я использую это, но он не всегда на 100% правильный. Возможно, в 70% случаев он дает правильные предложения. – InQusitive 27 February 2018 в 15:25

Чтобы завершить это обсуждение, препроцессор c ++ завершен. Это семантическое свойство, независимо от того, является ли включение излишним. Следовательно, из теоремы Райса следует, что неразрешимо, является ли включение избыточным или нет. Там НЕ МОЖЕТ быть программа, которая (всегда правильно) определяет, является ли добавление излишним.

2
ответ дан Algoman 31 August 2018 в 09:44
поделиться
  • 1
    Просил ли я «всегда правильно»? решение? Этот ответ не очень продуктивен для обсуждения. – shoosh 7 April 2014 в 21:03
  • 2
  • 3
    Между всеми СПЕЦИАЛИЗАЦИЯми о том, насколько тяжело это будет и как вы МОЖЕТЕ решить одно препятствие, я дал вам только 100% правильный ответ. Я нахожу довольно дерзким сказать, что это было неэффективно ... – Algoman 9 April 2014 в 09:50
  • 4
    Я помнил, что теорема Райса гласит: «Не может быть программы, которая всегда может проверить, разрешает ли данная программа эту избыточную проблему». Могут быть несколько программ, которые решают проблему избыточных включений. – Zhe Yang 13 January 2016 в 15:20
  • 5
    лично я нашел, что вход @ Algoman очень полезен. заставляет меня понять, насколько сложно эта проблема. – bogardon 1 February 2017 в 07:09

Вот простой способ для перебора лишнего заголовка включает . Это не идеально, но устраняет «очевидные» ненужные включения.

Доступ к скриптам можно получить непосредственно в GitHub.

1
ответ дан ap-osd 31 August 2018 в 09:44
поделиться

Я пробовал использовать Flexelint (unix-версия PC-Lint) и имел несколько смешанные результаты. Скорее всего, потому, что я работаю над очень большой и узловатой базой кода. Я рекомендую внимательно изучить каждый файл, который сообщается как неиспользованный.

Основное беспокойство - ложные срабатывания. Несколько включений одного и того же заголовка сообщаются как ненужный заголовок. Это плохо, потому что Flexelint не сообщает вам, в какую строку заголовок включен или где он был включен ранее.

Один из способов, по которому автоматические инструменты могут ошибиться:

В A .hpp:

class A { 
  // ...
};

В B.hpp:

#include "A.hpp

class B {
    public:
        A foo;
};

В C.cpp:

#include "C.hpp"  

#include "B.hpp"  // <-- Unneeded, but lint reports it as needed
#include "A.hpp"  // <-- Needed, but lint reports it as unneeded

Если вы слепо следуете сообщениям из Flexelint вы отбросите свои зависимости #include. Есть больше патологических случаев, но в основном вам нужно будет проверить заголовки самостоятельно для достижения наилучших результатов.

Я очень рекомендую эту статью о Physical Structure и C ++ из блога Игры изнутри. Они рекомендуют комплексный подход к очистке #include mess:

Рекомендации

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

  1. Каждый файл cpp включает в себя собственный заголовочный файл. [snip]
  2. Заголовочный файл должен содержать все файлы заголовков, необходимые для его анализа. [snip]
  3. В файле заголовка должно быть минимальное количество файлов заголовков, необходимых для его анализа. [snip]
2
ответ дан Ben Martin 31 August 2018 в 09:44
поделиться
  • 1
    Книга Лакоса отлично подходит для образования - помимо его устаревших наблюдений за технологией компилятора. – Tom 6 March 2009 в 02:38

Существует два типа избыточных файлов #include:

  1. Файл заголовка, который фактически не нужен модулю (.c, .cpp) на всех
  2. Заголовочный файл является необходимостью модуля, но включается не один раз, прямо или косвенно.

В моем опыте есть два способа:

  • ] gcc -H или cl.exe / showincludes (проблема разрешения 2) В реальном мире вы можете экспортировать CFLAGS = -H перед make, если все Makefile не переопределяет опции CFLAGS. Или, как я использовал, вы можете создать оболочку cc / g ++, чтобы добавить опции -H принудительно к каждому вызову $ (CC) и $ (CXX). и добавьте каталог оболочки в переменную $ PATH, тогда ваш make будет использовать команду wrapper вместо этого. Конечно, ваша оболочка должна вызывать настоящий gcc-компилятор. Эти трюки необходимо изменить, если ваш Makefile напрямую использует gcc. вместо $ (CC) или $ (CXX) или подразумеваемых правил. Вы также можете скомпилировать один файл, настроив его с помощью командной строки. Но если вы хотите очистить заголовки для всего проекта. Вы можете записать весь вывод: make clean make 2> & amp; 1 | tee result.txt
  • PC-Lint / FlexeLint (разрешить проблему как с 1, так и 2), обязательно добавьте опции + e766, это предупреждение о: неиспользуемых файлах заголовков. pclint / flint -vf ... Это приведет к включению заголовочных файлов pclint, вложенные файлы заголовков будут соответствующим образом отступы.
1
ответ дан Benjamin 31 August 2018 в 09:44
поделиться

Gimpel Software PC Lint может сообщать, когда включенный файл был включен более одного раза в блок компиляции, но он не может найти файлы, которые не нужны в том, как вы смотрите для.

Изменить: Он может. См. Ответ itsmatt

0
ответ дан Community 31 August 2018 в 09:44
поделиться
  • 1
    Вы уверен об этом? Я не использовал FlexeLint (то же, что и PCL) через несколько лет на C ++-коде, но даже недавно на C-коде я мог бы поклясться, что видел пару сообщений (я думаю, это код 766?) О неиспользуемых файлах заголовков. Только что проверили (v8.0), см. Раздел 11.8.1. руководства. – Dan 5 March 2009 в 19:57
  • 2
    Да, см. Мое редактирование, указывающее на обновленный ответ itsmatt. – crashmstr 5 March 2009 в 20:50

CLion , C / C ++ IDE из JetBrains, обнаруживает избыточность, включает в себя готовые. Они выделены серым цветом в редакторе, но функции optimize включают в текущий файл или весь проект .

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

0
ответ дан congusbongus 31 August 2018 в 09:44
поделиться

Извините, что (пере) сообщение здесь, люди часто не раздают комментарии.

Проверьте мой комментарий на crashmstr, FlexeLint / PC-Lint сделает это за вас. Информационное сообщение 766. В этом разделе обсуждается раздел 11.8.1 моего руководства (версия 8.0).

Кроме того, и это важно, продолжайте повторять, пока сообщение не исчезнет. Другими словами, после удаления неиспользуемых заголовков повторно запустите lint, после того, как вы удалите ненужные заголовки, больше файлов заголовков могут стать «ненужными». (Это может показаться глупым, медленно прочитайте его и проанализируйте его, это имеет смысл.)

5
ответ дан Dan 31 August 2018 в 09:44
поделиться
  • 1
    Я точно знаю, что вы имеете в виду, и моя реакция была «Ewwww». Я ненавижу такой код. – David Thornley 5 March 2009 в 20:12

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

5
ответ дан Dan Olson 31 August 2018 в 09:44
поделиться

Браузер рефакторинга CScout может обнаруживать избыточные директивы include в коде C (к сожалению, не C ++). Вы можете найти описание того, как это работает в этой статье журнала .

7
ответ дан Diomidis Spinellis 31 August 2018 в 09:44
поделиться

Вы можете написать быстрый скрипт, который удаляет единственную директиву #include, компилирует проекты и записывает имя в #include и файл, из которого он был удален, в случае, если ошибки компиляции не были.

Пусть он работает ночью, а на следующий день у вас будет 100% правильный список включенных файлов, которые вы можете удалить.

Иногда грубая сила работает: -)


edit: а иногда это не так :-). Вот немного информации из комментариев:

  1. Иногда вы можете удалить два файла заголовка отдельно, но не оба вместе. Решение состоит в том, чтобы удалить файлы заголовков во время прогона и не возвращать их обратно. Это найдет список файлов, которые можно безопасно удалить, хотя может быть решение с большим количеством файлов для удаления, которые этот алгоритм не найдет. (это жадный поиск по пространству включенных файлов для удаления. Он найдет только локальный максимум)
  2. Могут быть незначительные изменения в поведении, если у вас есть несколько макросов, переопределенных по-разному в зависимости от некоторых #ifdefs. Я думаю, что это очень редкие случаи, и тесты единиц, которые являются частью сборки, должны улавливать эти изменения.
5
ответ дан Gilad Naor 31 August 2018 в 09:44
поделиться
  • 1
    Будьте осторожны - скажем, есть два файла заголовка, которые включают определение чего-то. Вы можете удалить оба, но не оба. Вам нужно быть более основательным в своем подходе. – Dominic Rodger 5 March 2009 в 15:21
  • 2
    Возможно, это то, что вы имели в виду, но сценарий, который удаляет один, включает, и оставляет последний удаленный include, если он был успешно удален, сделал бы трюк. – Dominic Rodger 5 March 2009 в 15:21
  • 3
    Плохая идея. Если заголовочный файл # определит константу BLAH, а другой файл заголовка проверяет #ifdef BLAH, удаление первого файла заголовка все еще может успешно скомпилироваться, но ваше поведение изменилось. – Graeme Perrow 5 March 2009 в 15:31
  • 4
    Это также может вызвать проблемы с заголовками системы, поскольку в разных реализациях могут быть разные вещи, включенные в #include & lt; vector & gt ;. Даже если вы придерживаетесь одного компилятора, заголовки могут меняться в разных версиях. – David Thornley 5 March 2009 в 15:52
  • 5

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

Я просмотрел этот блог , и автор немного рассказал о настройке PCLint, чтобы найти неиспользованные. Возможно, стоит посмотреть.

15
ответ дан itsmatt 31 August 2018 в 09:44
поделиться
  • 1
    Хорошая находка! Я должен буду использовать это. – crashmstr 5 March 2009 в 15:17
  • 2
    хороший. слишком плохой PC-lint не является бесплатным ... – shoosh 5 March 2009 в 15:26
  • 3
    Я регулярно использую PCLint, и это говорит мне о неиспользуемых заголовках. Я стараюсь прокомментировать заголовок #include и перекомпилировать, чтобы убедиться, что заголовок действительно не используется ... – Harold Bamford 5 March 2009 в 18:23
  • 4
    Спасибо за подтверждение, Гарольд. – itsmatt 5 March 2009 в 18:26
  • 5
    слишком дорого. не жизнеспособный инструмент для масс. – user 2 January 2011 в 08:08

Проблема с обнаружением избыточных включает в себя то, что она не может быть просто средством проверки зависимостей типа. Неверный include - это файл, который не дает ничего полезного для компиляции и не изменяет другой элемент, от которого зависят другие файлы. Существует много способов, которыми файл заголовка может изменять компиляцию, например, определяя константу, переопределяя и / или удаляя используемый макрос, добавляя пространство имен, которое изменяет поиск имени каким-либо образом вниз по строке. Чтобы обнаружить такие элементы, как пространство имен, вам нужно гораздо больше, чем препроцессор, вам фактически нужен полный компилятор.

Lint - это скорее средство проверки стиля и, конечно же, не будет иметь этой полной возможности.

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

23
ответ дан Jonathan Leffler 31 August 2018 в 09:44
поделиться
  • 1
    Ничего из этого не будет проблемой, если файлы include будут выложены хорошо. Если вам когда-либо понадобится включить файл A перед файлом B, вы делаете это неправильно (и я работал над проектами, где они делали это неправильно). – David Thornley 5 March 2009 в 15:50
  • 2
    @ Давид, да, но это зависит от лет разработчиков, прежде чем делать это правильно. Я могу с большой уверенностью сказать, что шансы на то, что это происходит, благоприятствуют дому, а не вам :( – JaredPar 5 March 2009 в 16:38
  • 3
    Да, но я вообще узнаю об этом при изменении программы, и вдруг у меня возникла ошибка компиляции (если мне повезет) или непонятная ошибка. Это похоже на то, что файлы #include честны, по крайней мере, в конечном итоге. – David Thornley 5 March 2009 в 20:10
  • 4
    Я бы сказал прямо противоположное. Все, что вам нужно, это проверка соответствия типов. Он может не скомпилироваться после того, как вы упорядочили, соответственно, но это проблемы, с которыми нужно иметь дело в любом случае. – Benoît 5 March 2009 в 21:30
  • 5
    @Benoit, тогда вы будете игнорировать класс проблем, которые скомпилируются, но семантически меняют смысл вашей программы. Подумайте, как #define в одном файле может изменить ветвь #if в другой. Удаление заголовка может позволить это скомпилировать с разными результатами – JaredPar 5 March 2009 в 21:45

Google cppclean (ссылки на: скачать , documentation ) может найти несколько категорий проблем C ++, и теперь он может найти лишние #includes.

Также есть инструмент, основанный на Clang, include-what-you-use , который может это сделать. include-what-you-use может даже предлагать передовые декларации (так что вам не нужно так много #include) и, возможно, очистите свои #includes для вас.

В текущих версиях Eclipse CDT также встроена эта функциональность: перейдите в меню «Источник» и нажмите «Упорядочить» включит в алфавитном порядке ваши # include, добавьте заголовки, которые Eclipse думает, что вы используя без прямого их включения, и комментирует любые заголовки, которые, по вашему мнению, вам не нужны. Однако эта функция не на 100% надежна.

135
ответ дан Nick 31 August 2018 в 09:44
поделиться
  • 1
    Это происходит сейчас. Я только начинаю использовать его. См. Мою записку здесь. [Д0] stackoverflow.com/questions/1301850/… – Chance 18 August 2011 в 18:39
  • 2
    Репозиторий cppclean не работает, теперь вы можете получить его здесь: bitbucket.org/robertmassaioli/cppclean (исходный сайт по-прежнему полезен для использования в некоторых примерах) – Nick 14 June 2013 в 23:45
  • 3
    Я обновил ссылку на поддерживаемую вилку cppclean: github.com/myint/cppclean – BenC 29 August 2014 в 13:20
  • 4
    Обратите внимание, что cppclean, похоже, находит их только в файлах заголовков, а не в файлах cpp, из документа: & quot; Необязательный #includes в заголовочных файлах & quot ;. – Zitrax 9 August 2016 в 09:52
  • 5
    @wizurd - Я не поддерживал последние разработки в Eclipse CDT, но я так не думаю. iwyu является тщательным и относительно медленным. Анализ Eclipse CDT быстрый (интерактивный) и, когда я его тестировал, менее точен. – Josh Kelley 12 July 2018 в 15:19

Если вы используете Eclipse CDT, вы можете попробовать http://includator.com , который бесплатно для бета-тестеров (на момент написания этой статьи) и автоматически удаляет лишние #includes или добавляет недостающие , Для тех пользователей, которые имеют FlexeLint или PC-Lint, и используют Elitpse CDT, http://linticator.com может быть вариантом (также бесплатным для бета-теста). Хотя он использует анализ Lint, он обеспечивает быстрые исправления для автоматического удаления лишних операторов #include.

4
ответ дан PeterSom 31 August 2018 в 09:44
поделиться
  • 1
    Лицензия на это дополнение - смешное 830 швейцарских франков !!!! – Jacko 11 December 2013 в 05:02
  • 2
    Причиной этого является то, что наш бухгалтерский отдел не может начислять меньшие суммы. Если вы посчитаете время, которое вы можете сохранить, это не так необоснованно. Однажды у нас есть возможность получать платежи по кредитным картам, мы можем значительно снизить цену. Другим вариантом будет спонсор наших усилий в области развития. Наша модель финансирования требует от нас получения прибыли для финансирования нашей исследовательской работы. Я был бы рад продать лицензии намного дешевле, но не могу. Может быть, мы внесем его в CDT, и вы получите его бесплатно, но я должен как-то финансировать. Я забыл, вы можете попробовать бесплатно! – PeterSom 11 December 2013 в 10:02

Возможно, немного поздно, но однажды я нашел скрипт Perl WebKit, который сделал именно то, что вы хотели. Мне нужно немного адаптироваться (я не очень разбираюсь в perl), но он должен сделать трюк:

http://trac.webkit.org/browser/branches/ old / safari-3-2-branch / WebKitTools / Scripts / find-extra-includes

(это старая ветка, потому что у trunk больше нет файла)

1
ответ дан rubenvb 31 August 2018 в 09:44
поделиться

В этой статье объясняется метод #include удаления с использованием разбора Doxygen. Это всего лишь скрипт perl, поэтому он довольно прост в использовании.

2
ответ дан Steve Gury 31 August 2018 в 09:44
поделиться
  • 1
    Сценарий находит, что некоторые из них включают в себя удаление, но он также содержит множество включений, которые нельзя удалить. Кажется, что он не поддерживает перечисление класса, также кажется, что он имеет плохое время с макросом, а иногда и с пространством имен. – Baptiste Wicht 30 October 2012 в 04:53

Существует бесплатный инструмент Include File Dependencies Watcher , который можно интегрировать в визуальную студию. Он показывает лишние # включает красный.

2
ответ дан Vladimir 31 August 2018 в 09:44
поделиться
  • 1
    Я просто попробовал, и связь была нарушена для меня. – drescherjm 22 September 2016 в 17:35
Другие вопросы по тегам:

Похожие вопросы: