Поделиться через


Методы отладки CRT

При отладке программы, используюющей библиотеку времени выполнения C, эти методы отладки могут оказаться полезными.

Использование библиотеки отладки CRT

Библиотека среды выполнения C (CRT) обеспечивает обширную поддержку отладки. Чтобы использовать одну из библиотек отладки CRT, необходимо связаться с и скомпилировать с /DEBUG /MDdпомощью , /MTdили ./LDd

Основные определения и макросы для отладки CRT можно найти в файле заголовка<crtdbg.h> .

Функции в отладочных библиотеках CRT компилируются с отладочными сведениями (/Z7, /Zd, /Zi, /ZI (формат отладочной информации)) и без оптимизации. Некоторые функции содержат утверждения для проверки передаваемых им параметров, для них приведен исходный код. Исходный код позволяет войти в функцию CRT, чтобы убедиться, что она работает в соответствии с ожиданиями, а также проверить функцию на наличие некорректных параметров или состояний памяти. (Некоторые технологии CRT являются частными и не предоставляют исходный код для обработки исключений, плавающей запятой и нескольких других подпрограмм.)

Дополнительные сведения о различных библиотеках времени выполнения см. в разделе Библиотеки времени выполнения C.

Макросы для создания отчетов

Для отладки можно использовать макросы и _RPTFn макросы, определенные в<crtdbg.h>, для замены использования инструкцийprintf._RPTn Вам не нужно заключать их в #ifdef директивы, так как они автоматически исчезают в сборке выпуска, когда _DEBUG они не определены.

Макрос Description
_RPT0, , _RPT1_RPT2, _RPT3_RPT4 Выводит строку сообщения и от нуля до четырех аргументов. Для _RPT1 этого _RPT4строка сообщения служит строкой форматирования в стиле печати для аргументов.
_RPTF0, , _RPTF1_RPTF2, _RPTF3_RPTF4 То же, что _RPTnи макросы, но эти макросы также выводит имя файла и номер строки, где находится макрос.

Рассмотрим следующий пример:

#ifdef _DEBUG
    if ( someVar > MAX_SOMEVAR )
        printf( "OVERFLOW! In NameOfThisFunc( ),
               someVar=%d, otherVar=%d.\n",
               someVar, otherVar );
#endif

Этот код выводит значения someVar и otherVar в stdout. Вызов _RPTF2 можно применить для отчета об этих значениях плюс имя файла и номер строки:

if (someVar > MAX_SOMEVAR) _RPTF2(_CRT_WARN, "In NameOfThisFunc( ), someVar= %d, otherVar= %d\n", someVar, otherVar );

Некоторым приложениям может потребоваться отладочная отчетность о том, что макросы, предоставленные библиотекой времени выполнения C, не предоставляются. В таком случае можно написать свой собственный макрос, удовлетворяющий конкретным требованиям. Например, в одном из файлов заголовков можно включить следующий код, чтобы определить макрос с именем ALERT_IF2:

#ifndef _DEBUG                  /* For RELEASE builds */
#define  ALERT_IF2(expr, msg, arg1, arg2)  do {} while (0)
#else                           /* For DEBUG builds   */
#define  ALERT_IF2(expr, msg, arg1, arg2) \
    do { \
        if ((expr) && \
            (1 == _CrtDbgReport(_CRT_ERROR, \
                __FILE__, __LINE__, msg, arg1, arg2))) \
            _CrtDbgBreak( ); \
    } while (0)
#endif

Один вызов ALERT_IF2 может выполнять все функции printf кода:

ALERT_IF2(someVar > MAX_SOMEVAR, "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n", someVar, otherVar );

Пользовательский макрос можно легко настроить для передачи большего или меньшего объема информации в разные места назначения. Этот подход полезен при развитии требований к отладке.

Написание функций отладочных ловушек

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

Функции-ловушки клиентского блока

Если нужно проверить или вывести данные, хранящиеся в блоках типа _CLIENT_BLOCK, можно написать для этого специальную функцию. Функция, написаемая, должна иметь прототип, аналогичный следующему, как определено в<crtdbg.h>:

void YourClientDump(void *, size_t)

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

После установки функции перехватчика с помощью _CrtSetDumpClient он будет вызываться каждый раз при _CLIENT_BLOCK дампах блока. _CrtReportBlockType можно применять для получения сведений о типе или подтипе выводимых блоков.

Указатель на передаваемую _CrtSetDumpClient функцию имеет тип _CRT_DUMP_CLIENT, как определено в<crtdbg.h>:

typedef void (__cdecl *_CRT_DUMP_CLIENT)
   (void *, size_t);

Функции-ловушки выделения

Функция перехватчика выделения, установленная с помощью _CrtSetAllocHook, вызывается при каждом выделении памяти, перемещении или освобождении. Этот тип ловушек можно использовать для различных целей. Используйте их, например, для проверки, как приложение обрабатывает ситуации недостатка памяти, или для оценки шаблонов выделения, или для регистрации данных о выделении для дальнейшего анализа.

Примечание.

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

Функция-ловушка выделения должна иметь следующий пример:

int YourAllocHook(int nAllocType, void *pvData,
        size_t nSize, int nBlockUse, long lRequest,
        const unsigned char * szFileName, int nLine )

Указатель, который _CrtSetAllocHook передается типом _CRT_ALLOC_HOOK, как определено в<crtdbg.h>:

typedef int (__cdecl * _CRT_ALLOC_HOOK)
    (int, void *, size_t, int, long, const unsigned char *, int);

Когда библиотека времени выполнения вызывает ваш перехватчик, аргумент указывает, nAllocType какая операция выделения будет выполнена (_HOOK_ALLOC, _HOOK_REALLOCили _HOOK_FREE). В случае освобождения или перераспределения, pvData содержит указатель на пользовательскую часть освобождаемого блока. Однако в случае выделения памяти этот указатель пуст, так как выделение еще не произошло. Остальные аргументы содержат размер выделения, тип блока, последовательный номер запроса и указатель на имя файла. Если он доступен, аргументы также включают номер строки, в которой было выполнено выделение. После того как функция перехватчика выполняет любой анализ и другие задачи, которые его автор хочет, она должна вернуться TRUE, указывая, что операция выделения может продолжаться, или FALSE, указывая, что операция должна завершиться ошибкой. Простой перехватчик этого типа может проверить объем памяти, выделенный до сих пор, и вернуть FALSE , если эта сумма превысила небольшой предел. Затем приложение будет испытывать такие ошибки выделения, которые обычно возникают, только если доступная память была низкой. Более сложные ловушки могут отслеживать структуру выделения, анализировать использование памяти или сообщать о возникновении какой-либо определенной ситуации.

Выделение перехватчиков и выделений памяти CRT

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

if ( nBlockUse == _CRT_BLOCK )
    return( TRUE );

Если ловушка обрабатывает блоки _CRT_BLOCK, то любая вызываемая в ней функция CRT может привести к выполнению в программе бесконечного цикла. Например, printf осуществляет внутреннее выделение. Если код перехватчика вызывается printf, то результирующее выделение приведет к повторному вызову перехватчика, который снова вызовет printf и т. д., пока стек не переполнен. Если нужен отчет об операциях выделения _CRT_BLOCK, есть способ обойти это ограничение — для форматирования и вывода использовать функции Windows API вместо функций CRT. Так как функции API-интерфейсов Windows не используют кучу библиотеки CRT, они не могут привести к выполнению в приложении бесконечного цикла.

При проверке исходных файлов библиотеки времени выполнения вы увидите, _CrtDefaultAllocHook что функция перехватчика выделения по умолчанию (которая просто возвращается TRUE), находится в отдельном файле собственного debug_heap_hook.cppфайла. Если вы хотите, чтобы перехватчик выделения был вызван даже для выделения, сделанных кодом запуска во время выполнения перед функцией приложения main , вы можете заменить эту функцию по умолчанию одной из собственных, а не использовать _CrtSetAllocHook.

Отчетные функции-ловушки

Функция перехватчика отчета, установленная с помощью _CrtSetReportHook, вызывается каждый раз, когда _CrtDbgReport создает отчет отладки. Помимо всего прочего их можно использовать для фильтрации отчетов, которые позволяют отобрать выделения конкретного типа. Функция перехватчика отчета должна иметь прототип, как в следующем примере:

int AppReportHook(int nRptType, char *szMsg, int *retVal);

Указатель, который _CrtSetReportHook передается в тип _CRT_REPORT_HOOK, как определено в <crtdbg.h>:

typedef int (__cdecl *_CRT_REPORT_HOOK)(int, char *, int *);

Когда библиотека времени выполнения вызывает функцию перехватчика, nRptType аргумент содержит категорию отчета (_CRT_WARNили_CRT_ASSERT_CRT_ERROR), szMsg содержит указатель на полностью собранную строку сообщения отчета и retVal указывает, следует ли _CrtDbgReport продолжить нормальное выполнение после создания отчета или запустить отладчик. retVal(Значение нуля продолжает выполнение, значение 1 запускает отладчик.)

Если перехватчик полностью обрабатывает сообщение, чтобы дальнейшие отчеты не требовались, он должен вернуться TRUE. Если он возвращается FALSE, _CrtDbgReport сообщение будет сообщаться обычно.

В этом разделе

  • Версии отладки функций выделения кучи

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

  • Сведения о куче отладки CRT

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

  • Поиск утечек памяти с помощью библиотеки CRT

    Рассматриваются способы обнаружения и изоляции утечек памяти с помощью отладчика и библиотеки времени выполнения языка C (CRT).

См. также