Подтвердить что ты не робот

Почему не известны константы # define'd для отладчика?

При отладке кода я довольно часто хочу знать значение констант # define'd. Но отладчик, похоже, не знает своих значений. Это означает, что я должен преследовать поиск путей включения и т.д., Чтобы найти строку #define. Есть ли какой-то трюк, чтобы сделать это проще?

ОБНОВЛЕНИЕ: Я должен был присвоить зеленый тик Тони Д за его подробный ответ на заголовок вопроса, но я также поддержал использование const вместо #define (я также тестировал что enum работает тоже). Наконец, использование F12 для поиска исходной строки #define было еще одной хорошей идеей.

4b9b3361

Ответ 1

В течение 10 минут на Google стоит, похоже, Visual Studio не поддерживает это.

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

Чтобы сначала перефразировать и сбить общее, но фиктивное объяснение этого: существует концептуально отличный шаг предварительной обработки, который заменяет текст для использования макросов препроцессора перед началом "правильной" компиляции, но там действительно без причины этап предварительной обработки не может передавать запись инструкций #define и #undef ine для включения с другой информацией об отладке.

Что такое боль, так это то, что интуитивно и обычно считается "#define - константа препроцессора" не похоже на...

const Some_Type some_identifier = some_value;

... в том, что последнее имеет конкретное место в иерархии пространства имен приложений и действительно не может быть изменено, тогда как a #define может быть #undef -ined и ref #define d any количество раз, так что "значение" макроса препроцессора в конкретной строке кода может зависеть от того, как эта строка была включена в блок перевода: каждое включение одной и той же строки в каждую единицу перевода может иметь другое значение (или не иметь значения) для этого макроса.

По этой причине отображение "значения" макроса при отладке через некоторый код проблематично - оно гарантировано только для одного значения в определенной строке в конкретной единицы перевода, но программисты обычно хотят, чтобы отладчики показывать и перемещать программы в терминах строк в исходных файлах.

Рассмотрим:

use_x.h

class T ## X {
    void g() { ... }
};

some_app.cc

#define X 2783
#include "use_x.h"
#undef X
#define X 2928
#include "use_x.h"
void f() {
    const int last_x = X;
}

Если ваш отладчик, шаг за шагом f() выше, X можно назвать 2928, но что, если вы переходите через версию g() - отладчик будет трудно понять, что некоторые соединение между именем класса и значением X, используемым для его создания, или разработка того, что отображать другим способом....

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

Итак, некоторые цепочки инструментов (компиляторы/debug-info-encodings/debuggers) просто не покупают этот беспорядок. Более эффективные инструменты могут отслеживать простые случаи, а затем показывать ничего - или список возможных значений - для случаев, слишком сложных для анализа. Отображение неправильных значений намного хуже, чем ничего.


Это не помогает в отладчике, но когда необходимо пересмотреть значения макросов/подстановок, вы можете попробовать cl /E (для GCC/clang опцию -E) для предоставления предварительно обработанного вывода для единицы перевода - вы можете затем посмотрите, какие подстановки были сделаны препроцессором.

Ответ 2

Макросы оцениваются и разрешаются препроцессором перед компиляцией. Это не только то, что скомпилированная программа не знает своих значений: скомпилированная программа не содержит никаких следов. Нет ничего, чтобы ваш отладчик мог проверить.

Рассмотрим макросы как инструмент генерации кода, и все станет ясно.

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

Ответ 3

'# Определяемые константы неизвестны отладчику, поскольку они предварительно обработаны перед компиляцией, и их появление в коде заменяется значением.

Если вы хотите постоянное значение, почему бы не использовать const? Таким образом, вы можете увидеть значение в отладчике, а также заставить компилятор проверить, где вы ошибочно пытаетесь изменить значение в коде. #define не имеет такой безопасности.

Ответ 4

Что касается "Visual Studio", во время предварительной обработки анализируется #define X 3, и все видимости X заменяются на 3. Таким образом, когда вы наводите на нее курсор мыши, отладчик не будет показывать свое значение, как в любом другом заявлении, которое имеет "жестко закодированное" значение.

int res = y + 3;

Если вы переместите указатель мыши на 3, он не покажет вам 3 в плавающем окне.

Ответ 5

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

дополнение: Может быть, действительно полезно.. Надеюсь:) Я больше не использую Visual Studio, поэтому я не уверен на 100%, если это возможно в 2015 году, но: - установить препроцесс файла в yes в свойствах конфигурации → C/С++ → препроцессор. - визуальная студия, используемая для создания файла .i, и я надеюсь, что 2015 все равно сделает то же самое, в следующий раз, когда вы скомпилируете свою программу, так как это вывод препроцессора. - открыв этот .i файл, вы можете хотя бы увидеть, что представляет собой фактическое расширенное значение вашего макроса, а также ввести это значение в окне просмотра во время отладки.

который просто стоил бы вам дополнительной компиляции, но поможет вам во второй раз, экономя драгоценное время, вы можете тратить на другие вещи, чем на палубное погружение:)

Ответ 6

Выберите интересующий вас макрос, на строке, которую вы хотите узнать о ее значении.

Нажмите F12.

Это перейдет к его определениям (как лучше всего может работать компилятор: данная строка кода может иметь несколько определений для одного и того же #define!).

Ответ 7

#define one 1

Это просто замена текста. Даже компилятор не знает, что стоит за этим "1" в коде.

Макросы оцениваются препроцессором до этапа компиляции/компоновки.

Подробнее о этапах компиляции: Как работает процесс компиляции/компоновки?