Советы и инструменты для поиска непревзойденных указаний на фигурные скобки/препроцессора

Это одна из самых страшных ошибок компилятора C/С++:

file.cpp(3124): фатальная ошибка C1004: обнаружен неожиданный конец файла

file.cpp включает в себя почти сто файлов заголовков, которые, в свою очередь, включают другие файлы заголовков. Это более 3000 строк. Код должен быть модульным и структурированным, а исходные файлы - меньше. Мы должны реорганизовать его. Как программист всегда есть список желаний для улучшения вещей.

Но прямо сейчас код беспорядок, и крайний срок не за горами. Где-то среди всех этих строк, возможно, в одном из включенных заголовочных файлов, а не в самом исходном файле &mdash, там, по-видимому, непревзойденная скобка, непревзойденный #ifdef или аналогичный. Проблема в том, что когда чего-то не хватает, компилятор не может сказать мне, где он отсутствует. Он просто знает, что, когда он достиг конца файла, он не находился в правильном состоянии парсера.

Можете ли вы предложить некоторые инструменты или другие рекомендации/методологии, которые помогут мне найти причину ошибки?

Ответы

Ответ 1

Если #includes находятся в одном месте в исходном файле, вы можете попробовать положить блуждающую закрывающую фигуру между #includes. Если при компиляции вы получаете ошибку "непревзойденной замыкающей скобки", вы знаете, что все балансы до этого момента. Это медленный метод, но это может помочь вам определить проблему.

Ответ 2

Один подход: если у вас есть Notepad ++, откройте все файлы (нет проблем с открытием 100 файлов), найдите {и} (Поиск → Найти → Найти во всех открытых документах), обратите внимание на разницу в count (следует 1). Случайно закройте 10 файлов и посмотрите, не отличается ли разница в счете 1, если это так, иначе проблема находится в одном из этих файлов. Повторить.

Ответ 3

Полезный совет:

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

При условии, что каждый заголовок включает в себя свои собственные зависимости (который является большим "предоставленным" ), это должно дать вам лучшую идею, какой заголовок вызывает проблему.

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

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

Еще один удобный совет, который сейчас слишком поздно:

Проверяйте чаще (на частной ветке, чтобы сохранить незавершенный код из всех остальных способов). Таким образом, когда все становится противно, вы можете отличить последнее компилируемое и сосредоточиться на измененных строках.

Ответ 4

Советов:

  • внести небольшие изменения и перекомпилировать после каждого небольшого изменения
  • для непревзойденных фигурных скобок используйте редактор /IDE, поддерживающий hipighting match brace match
  • Если все остальное не срабатывает, метод Oldie для комментирования блоков кода с использованием метода двоичной отбивки работает для меня

Ответ 5

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

EDIT: Помогает ли это vim script? Кажется, подсветка #ifdef.

Ответ 6

Можете ли вы создать script, который на самом деле делает все входящие, а затем записать весь материал во временный файл? Или попробуйте компилятор, чтобы помочь вам в этом? Затем вы можете использовать функции подсветки различных редакторов, чтобы найти проблему, и вы, вероятно, сможете идентифицировать файл. (Дополнительная помощь может заключаться в том, чтобы ваш script добавить комментарий к каждому включенному файлу).

Ответ 7

Это может не иметь отношения к вашей проблеме, но я получал ошибку "Неожиданное #else" при создании некоторых файлов заголовков в блоке # if/# else/# endif.

Я обнаружил, что если я установил проблемные модули, чтобы не использовать предварительно скомпилированные заголовки, проблема исчезла. Что-то делать с "#pragma hdrstop" не должно быть в пределах # if/# endif.

Ответ 8

Очень поздно, но на Linux вы можете использовать fgrep -o

  -o, --only-matching
          Print only the matched (non-empty) parts of a matching line,
          with each such part on a separate output line.

Итак, если вы fgrep -o {, тогда вы получите список всех открывающих фигур в вашем файле.

Затем вы можете передать это значение в wc -l, и это даст вам количество открывающих фигур в вашем файле.

С небольшим количеством арифметики bash вы можете сделать то же самое с закрытием фигурных скобок, а затем распечатать разницу.

В приведенном ниже примере я использую git status -s, чтобы получить вывод short-format всех измененных файлов из моего репозитория git, а затем я повторяю их, чтобы найти, какие файлы могут иметь несогласованные скобки

for i in $(git status -s | awk '{print $2}'); do 
    open=$(fgrep -o { $i | wc -l);   # count number of opening braces
    close=$(fgrep -o } $i | wc -l);  # count number of closing braces 
    diff=$((open-close));            # find difference
    echo "$diff : $i";               # print difference for filename
done

Ответ 9

Посмотрите на question (выделение непревзойденных скобок в vim)

Ответ 10

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

Ответ 11

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

Любой файл (скорее всего) будет иметь соответствующие фигурные скобки и макросы /endif.


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

foo.cpp

namespace Blah{
#include "bar.h"

bar.h:

}; /// namespace Blah

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

Я реализовал один в Ruby здесь, не стесняйтесь принимать и адаптироваться к вашим потребностям:

https://gist.github.com/movitto/6c6d187f7a350c2d71480834892552ab

Ответ 12

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

##ifdef FEATURE_X ...

Это сломало мир.

Легко искать, хотя.