Cpp: Как понять и / или отладить сложные макросы?
Я пытаюсь выучить приемы препроцессора, которые мне показались не такими простыми ( Можем ли мы иметь рекурсивные макросы?, Есть ли способ использовать строковое преобразование C++ для аргументов переменных макросов?, Препроцессор C++ __VA_ARGS__ количество аргументов, трюк макросов Variadic, ...).
Я знаю опцию -E, чтобы увидеть результат всего прохода препроцессора, но мне хотелось бы знать, существуют ли опции или средства, чтобы увидеть результат шаг за шагом. Действительно, иногда трудно проследить, что происходит, когда макрос вызывает макрос, вызывающий макрос... с механизмом отключения контекста, рисования синим цветом... Короче, мне интересно, является ли своего рода отладчик препроцессора с точками останова и другими инструменты существуют.
(Не отвечайте, что такое использование директив препроцессора опасно, безобразно, ужасно, не является хорошей практикой в C, создает нечитаемый код... Я знаю об этом, и это не вопрос).
3 ответа
Да, этот инструмент существует как функция Eclipse IDE. Я думаю, что по умолчанию способ доступа к этой функции - навести курсор на макрос, который вы хотите видеть развернутым (это покажет полное расширение), а затем нажмите F2
на вашей клавиатуре (появляется всплывающее окно, которое позволяет вам пройти через каждое расширение).
Когда я использовал этот инструмент, чтобы узнать больше о макросах, это было очень полезно. С небольшой практикой вам это больше не понадобится.
В случае, если кто-то не понимает, как использовать эту функцию, я нашел руководство по документации по Eclipse здесь.
Этот ответ на другой вопрос актуален.
Когда вы делаете странные трюки препроцессора (которые являются законными), полезно попросить компилятор сгенерировать предварительно обработанную форму (например, с помощью gcc -C -E
если используется GCC) и посмотрите на эту предварительно обработанную форму.
На практике для исходного файла foo.c
имеет смысл (иногда) получить предварительно обработанную форму foo.i
с gcc -C -E foo.c > foo.i
и посмотрите на это foo.i
,
Иногда даже имеет смысл получить это foo.i
без информации о линии. Хитрость здесь (удаление строки информации, содержащейся в строках, начинающихся с #
) будет делать:
gcc -C -E foo.c | grep -v '^#' > foo.i
Тогда вы могли бы indent foo.i
и скомпилируйте его, например, с gcc -Wall -c foo.i
; вы получите места ошибок в предварительно обработанном файле, и вы сможете понять, как вы это получили, и вернуться к своим макросам препроцессора (или их вызовам).
Помните, что препроцессор C - это в основном текстовое преобразование, работающее на уровне файлов. Макро-расширение нескольких строк невозможно изолировать (потому что предыдущие строки могли играть с #if
в сочетании с #define
-можно в приоре #include
-d файлы - или параметры препроцессора, такие как -DNDEBUG
перешел к gcc
или же g++
). В Linux см. Также feature_test_macros(7)
Известный пример расширения, которое работает по-разному при компиляции с или без -DNDEBUG
передается компилятору assert
, Значение assert(i++ > 0)
(очень неправильный код) зависит от этого и показывает, что расширение макроса не может быть выполнено локально (и вы могли бы представить, что какой-то предыдущий заголовок имеет #define NDEBUG 1
даже если конечно это плохой вкус).
Другой пример (на самом деле очень распространенный), где расширение макроса зависит от контекста, - это любой макрос, использующий __LINE__
или же __COUNTER__
...
NB. Вам не нужен Eclipse для всего этого, достаточно хороший редактор исходного кода (я предпочитаю emacs, но это дело вкуса): для задачи предварительной обработки вы можете использовать свой компилятор.
Единственный способ увидеть, что не так с вашим макросом, - это добавить опцию, которая сохранит временные файлы после завершения компиляции. Для gcc это -save-temps
вариант. Вы можете открыть .i
файл и расширенные макросы.
Индексаторы IDE (такие как Eclipse) не сильно помогут. Они не будут расширять (как указано в других ответах) макросы, пока не произойдет ошибка.