Técnicas de depuración de CRT
Al depurar un programa que usa la biblioteca en tiempo de ejecución de C, estas técnicas de depuración pueden ser útiles.
Uso de la biblioteca de depuración de CRT
La biblioteca en tiempo de ejecución de C (CRT) proporciona una amplia compatibilidad con la depuración. Para usar una de las bibliotecas de depuración de CRT, debe vincular con /DEBUG
y compilar con /MDd
, /MTd
o /LDd
.
Las principales definiciones y macros para la depuración de CRT se pueden encontrar en el archivo de<crtdbg.h>
encabezado.
Las funciones de las bibliotecas de depuración CRT se compilan con información de depuración (/Z7, /Zd, /Zi, /ZI (Formato de información de depuración)) y sin optimización. Algunas funciones contienen aserciones para comprobar los parámetros que se les pasan; además, se proporciona el código fuente. Con este código fuente, se pueden ejecutar las funciones CRT paso a paso para confirmar si las funciones se comportan como se esperaba y para comprobar si existen parámetros o estados de memoria incorrectos. (Algunas tecnologías de CRT son propietarias y no proporcionan código fuente para el control de excepciones, el punto flotante y otras rutinas).
Para obtener más información sobre las diversas bibliotecas en tiempo de ejecución que se pueden utilizar, vea Bibliotecas en tiempo de ejecución de C.
Macros para los informes
Para la depuración, puede usar las _RPTn
macros y _RPTFn
, definidas en<crtdbg.h>
, para reemplazar el uso de printf
instrucciones . No es necesario incluirlos en #ifdef
directivas, ya que desaparecen automáticamente en la compilación de versión cuando _DEBUG
no se define.
Macro | Descripción |
---|---|
_RPT0 , _RPT1 , _RPT2 , , _RPT3 , _RPT4 |
Escribe una cadena de mensaje y cero en cuatro argumentos. Para _RPT1 a través _RPT4 de , la cadena de mensaje actúa como una cadena de formato de estilo printf para los argumentos. |
_RPTF0 , _RPTF1 , _RPTF2 , , _RPTF3 , _RPTF4 |
Igual que _RPTn , pero estas macros también generan el nombre de archivo y el número de línea donde se encuentra la macro. |
Considere el ejemplo siguiente:
#ifdef _DEBUG
if ( someVar > MAX_SOMEVAR )
printf( "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n",
someVar, otherVar );
#endif
Este código genera los valores de someVar
y otherVar
en stdout
. Se puede utilizar la siguiente llamada a _RPTF2
para informar de estos mismos valores y, además, del nombre del archivo y el número de línea:
if (someVar > MAX_SOMEVAR) _RPTF2(_CRT_WARN, "In NameOfThisFunc( ), someVar= %d, otherVar= %d\n", someVar, otherVar );
Es posible que algunas aplicaciones necesiten informes de depuración que las macros proporcionadas con la biblioteca en tiempo de ejecución de C no proporcionan. En estos casos, puede escribir una macro diseñada específicamente para satisfacer sus propios requisitos. En uno de los archivos de encabezado, por ejemplo, podría incluir código como el siguiente para definir una macro denominada 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
Una llamada a ALERT_IF2
podría realizar todas las funciones del printf
código:
ALERT_IF2(someVar > MAX_SOMEVAR, "OVERFLOW! In NameOfThisFunc( ),
someVar=%d, otherVar=%d.\n", someVar, otherVar );
Puede cambiar fácilmente una macro personalizada para notificar más o menos información a distintos destinos. Este enfoque es útil a medida que evolucionan los requisitos de depuración.
Creación de funciones de enlace de depuración
Puede escribir varios tipos de funciones de enlace de depuración personalizadas que permiten insertar el código en algunos puntos predefinidos dentro del procesamiento normal del depurador.
Funciones de enlace con los bloques de tipo cliente
Si desea validar o informar del contenido de los datos almacenados en bloques _CLIENT_BLOCK
, puede escribir una función específicamente para ello. La función que escriba debe tener un prototipo similar al siguiente, tal como se define en<crtdbg.h>
:
void YourClientDump(void *, size_t)
En otras palabras, la función de enlace debe aceptar un void
puntero al principio del bloque de asignación, junto con un size_t
valor de tipo que indica el tamaño de la asignación y devolver void
. De lo contrario, su contenido está a tu altura.
Una vez que haya instalado la función de enlace mediante _CrtSetDumpClient, se llamará cada vez que se volque un _CLIENT_BLOCK
bloque. Se puede, entonces, utilizar _CrtReportBlockType para obtener información del tipo o subtipo de los bloques volcados.
El puntero a la función a la que se pasa _CrtSetDumpClient
es de tipo _CRT_DUMP_CLIENT
, como se define en<crtdbg.h>
:
typedef void (__cdecl *_CRT_DUMP_CLIENT)
(void *, size_t);
Funciones de enlace de asignación
Se llama a una función de enlace de asignación, instalada mediante _CrtSetAllocHook
, cada vez que se asigna, se reasigna o libera la memoria. Puede usar este tipo de enlace para muchos propósitos diferentes. Por ejemplo, puede usarlo para probar el modo en que una aplicación controla las situaciones de memoria insuficiente, como examinar pautas de asignación o registrar información de asignación para análisis posteriores.
Nota:
Tenga en cuenta la restricción sobre el uso de funciones de biblioteca en tiempo de ejecución de C en una función de enlace de asignación, que se describe en Asignaciones de enlaces de asignación y asignaciones de memoria de crt.
Una función de enlace de asignación debería tener un prototipo como este:
int YourAllocHook(int nAllocType, void *pvData,
size_t nSize, int nBlockUse, long lRequest,
const unsigned char * szFileName, int nLine )
El puntero al que se pasa _CrtSetAllocHook
es de tipo _CRT_ALLOC_HOOK
, como se define en<crtdbg.h>
:
typedef int (__cdecl * _CRT_ALLOC_HOOK)
(int, void *, size_t, int, long, const unsigned char *, int);
Cuando la biblioteca en tiempo de ejecución llama al enlace, el nAllocType
argumento indica qué operación de asignación se va a realizar (_HOOK_ALLOC
, _HOOK_REALLOC
o _HOOK_FREE
). En una operación de liberación o de reasignación, pvData
tiene un puntero al artículo de usuario del bloque que se va a liberar. Pero en el caso de una asignación, este puntero es nulo porque la asignación no se ha producido. Los argumentos restantes contienen el tamaño de la asignación, su tipo de bloque, un número de solicitud secuencial y un puntero al nombre de archivo. Si está disponible, los argumentos también incluyen el número de línea en el que se realizó la asignación. Después de que la función de enlace realice cualquier análisis y otras tareas que desee su autor, debe devolver , TRUE
lo que indica que la operación de asignación puede continuar o FALSE
, lo que indica que la operación debe producir un error. Un enlace simple de este tipo puede comprobar la cantidad de memoria asignada hasta ahora y devolver FALSE
si esa cantidad superó un límite pequeño. A continuación, la aplicación experimentaría el tipo de errores de asignación que normalmente se producirían solo cuando la memoria disponible era baja. Mediante enlaces más complejos, se podrían registrar pautas de asignación, analizar el uso de la memoria o informar de situaciones específicas.
Enlaces de asignación y asignaciones de memoria de CRT
Una restricción importante en las funciones de enlace de asignación es que deben omitir _CRT_BLOCK
explícitamente los bloques. Estos bloques son las asignaciones de memoria realizadas internamente por las funciones de la biblioteca en tiempo de ejecución de C si realizan alguna llamada a dichas funciones que asignan memoria interna. Pueden omitirse los bloques _CRT_BLOCK
si se incluye código como el siguiente al inicio de la función de enlace de asignación:
if ( nBlockUse == _CRT_BLOCK )
return( TRUE );
Si la función de enlace de asignación no omite los bloques _CRT_BLOCK
, cualquier función de la biblioteca en tiempo de ejecución de C a la que se llame en el enlace puede hacer que el programa quede atrapado en un bucle sin fin. Por ejemplo, printf
realiza una asignación interna. Si el código de enlace llama a printf
, la asignación resultante hará que se vuelva a llamar al enlace, que llamará printf
de nuevo, etc. hasta que se desborda la pila. Si necesita informar de las operaciones de asignación de _CRT_BLOCK
, una forma de evitar esta restricción consiste en utilizar funciones de la API de Windows, en vez de funciones en tiempo de ejecución de C, para operaciones de formato y salida. Como las API de Windows no utilizan el montón de la biblioteca en tiempo de ejecución de C, no bloquearán el enlace de asignación en un bucle sin fin.
Si examina los archivos de origen de la biblioteca en tiempo de ejecución, verá que la función de enlace de asignación predeterminada ( _CrtDefaultAllocHook
que simplemente devuelve TRUE
), se encuentra en un archivo independiente propio, debug_heap_hook.cpp
. Si desea que se llame al enlace de asignación incluso para las asignaciones realizadas por el código de inicio en tiempo de ejecución que se ejecuta antes de la función de la main
aplicación, puede reemplazar esta función predeterminada por una de sus propias, en lugar de usar _CrtSetAllocHook
.
Funciones de enlace de informe
Se llama a una función de enlace de informe, instalada mediante _CrtSetReportHook
, cada vez _CrtDbgReport
que genera un informe de depuración. Se puede utilizar, entre otras cosas, para filtrar informes que se concentran en determinados tipos de asignaciones. Una función de enlace de informe debe tener un prototipo como este ejemplo:
int AppReportHook(int nRptType, char *szMsg, int *retVal);
El puntero al que se pasa _CrtSetReportHook
es de tipo _CRT_REPORT_HOOK
, como se define en <crtdbg.h>
:
typedef int (__cdecl *_CRT_REPORT_HOOK)(int, char *, int *);
Cuando la biblioteca en tiempo de ejecución llama a la función de enlace, el nRptType
argumento contiene la categoría del informe (_CRT_WARN
, _CRT_ERROR
o _CRT_ASSERT
), szMsg
contiene un puntero a una cadena de mensaje de informe totalmente ensamblado y retVal
especifica si _CrtDbgReport
debe continuar la ejecución normal después de generar el informe o iniciar el depurador. (Un retVal
valor de cero continúa la ejecución, un valor de 1 inicia el depurador).
Si el enlace controla completamente el mensaje en cuestión, de modo que no se requiera ningún informe adicional, debe devolver TRUE
. Si devuelve FALSE
, _CrtDbgReport
notificará el mensaje normalmente.
En esta sección
Versiones de depuración de las funciones de asignación del montón
Describe las versiones especiales de depuración de las funciones de asignación del montón, entre las que se incluyen: cómo asigna CRT las llamadas, las ventajas de llamarlas explícitamente, cómo evitar la conversión, realizar un seguimiento de los tipos independientes de asignaciones en bloques de cliente y los resultados de no definir
_DEBUG
.Detalles del montón de depuración de CRT
Describe la administración de memoria y el montón de depuración, los tipos de bloques del montón de depuración, las funciones de informes de estado del montón de montón de montón y cómo usar el montón de depuración para realizar un seguimiento de las solicitudes de asignación.
Búsqueda de pérdidas de memoria mediante la biblioteca CRT
Explica técnicas para detectar y aislar pérdidas de memoria mediante el depurador y la biblioteca en tiempo de ejecución de C.