#
# Opciones para el compilador.
-CFLAGS=-ansi -pedantic -Wall -g3
+CFLAGS=-ansi -pedantic -Wall -g3 -DDEBUG
+CC=gcc-3.2
+# Pruebas.
+TESTS=dllist_test memdebug_test
# Programa a compilar.
-TARGETS=
+TARGETS=$(TESTS)
# Regla por defecto.
all: tp1
# Pruebas.
-tests: dllist_test
+tests: $(TESTS)
./dllist_test
+ ./memdebug_test
dllist_test: dllist.o
+memdebug_test: dllist.o meminfo.o memdebug.o
+
tp1: $(TARGETS)
# Regla para borrar.
#ifndef DLLIST_H
#define DLLIST_H
-
/** Tipo de dato booleano. */
typedef enum {
FALSE, /**< Falso. */
Puede suponerse que estas ecuaciones son válidas.
+\section conclusiones Conclusiones.
+
+Problemas:
+ - "Sobrecarga" de malloc. Lo hacía antes de un #include <stdlib.h> y me
+ tiraba un error porque la definicion de la stdlib me expandía el macro.
+ -
*/
--- /dev/null
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 20:08:45 ART 2003
+ *
+ * $Id$
+ */
+
+#include "memdebug.h"
+#include "dllist.h"
+#include "meminfo.h"
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/**
+ * Lista interna a utilizar en memdebug_malloc() y memdebug_free().
+ */
+static DLList* memdebug_list;
+
+/**
+ * FIXME la búsqueda se realiza de atrás hacia adelante para que sea más
+ * eficiente, ya que generalmente se borra primero la memoria que se pidió
+ * úitima.
+ */
+bool memdebug_DLList_find(DLList* list, void* ptr) {
+ MemInfo* i;
+ for (i = DLList_end(list); DLList_have_more(list); i = DLList_prev(list)) {
+ if (i->pointer == ptr) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+void memdebug_info_print(MemInfo* mi, FILE* fp) {
+ char fecha[30];
+ struct tm* ltime;
+ ltime = localtime(&(mi->time));
+ strftime(fecha, 30, "%c", ltime);
+ fprintf(fp, "0x%08X | %5u | %-25s | %-16s | %5u\n",
+ (size_t)(mi->pointer),
+ mi->bytes,
+ fecha,
+ mi->filename,
+ mi->fileline);
+}
+
+void memdebug_list_print(FILE* fp) {
+ MemInfo* mi;
+ fprintf(fp, "%-10s | %-5s | %-25s | %-16s | %-5s\n",
+ "Ptr",
+ "Bytes",
+ "Fecha",
+ "Archivo",
+ "Línea");
+ fprintf(fp, "-----------+-------+---------------------------+"
+ "------------------+------\n");
+ for (mi = DLList_begin(memdebug_list);
+ DLList_have_more(memdebug_list);
+ mi = DLList_next(memdebug_list)) {
+ memdebug_info_print(mi, fp);
+ }
+}
+
+void* memdebug_malloc(size_t bytes, const char* fname, size_t fline) {
+ void* ptr;
+ /* Si no está creada la lista global, la creo (o intento). */
+ if (!memdebug_list) {
+ memdebug_list = DLList_new();
+ /* Si no se puede crear la lista no reservo memoria, devuelvo NULL. */
+ if (!memdebug_list) {
+#ifdef DEBUG
+ fprintf(stderr, "%s: No se pudo crear la lista interna "
+ "(llamado desde %s, línea %i).\n",
+ __FILE__, fname, fline);
+#endif
+ return NULL;
+ }
+ }
+ /* Intento reservar memoria pedida. */
+ ptr = malloc(bytes);
+ /* Si se puedo reservar, creo un nuevo nodo y lo agrego a la lista. */
+ if (ptr) {
+ MemInfo* mi = MemInfo_new(ptr, bytes, fname, fline);
+ /* Si no se puede crear el nodo, devuelvo NULL. */
+ if (!mi || !DLList_push(memdebug_list, mi)) {
+#ifdef DEBUG
+ fprintf(stderr, "%s: No se pudo crear el nodo para 0x%X "
+ "(llamado desde %s, línea %u).\n",
+ __FILE__, (size_t)ptr, fname, fline);
+#endif
+ return NULL;
+ }
+ }
+ return ptr;
+}
+
+void memdebug_free(void* ptr) {
+ /* Busca en la lista y de encontrarlo nos lo deja en el elemento actual. */
+ if (memdebug_DLList_find(memdebug_list, ptr)) {
+ /* Lo encontró, elimino el nodo actual. */
+ DLList_remove_current(memdebug_list);
+#ifdef DEBUG
+ } else {
+ fprintf(stderr, "%s: No se encontro el ptr 0x%X en la lista.\n",
+ __FILE__, (size_t)ptr);
+#endif
+ }
+ /* Lo encuentre o no, trata de liberar la memoria. */
+ free(ptr);
+}
+
+void memdebug_end(void) {
+ /* Si hay una lista. */
+ if (memdebug_list) {
+ MemInfo* mi;
+ /* Imprimo la lista. */
+ memdebug_list_print(stderr);
+ /* Libero la memoria de cada elemento y cada puntero almacenado. */
+ while (!DLList_empty(memdebug_list)) {
+ mi = DLList_pop(memdebug_list);
+ free(mi->pointer);
+ MemInfo_delete(mi);
+ }
+ }
+}
+
--- /dev/null
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 20:08:45 ART 2003
+ *
+ * $Id$
+ */
+
+#ifndef MEMDEBUG_H
+#define MEMDEBUG_H
+
+#include "dllist.h"
+#include "meminfo.h"
+/* Para usar FILE. */
+#include <stdio.h>
+
+/**
+ * @todo FIXME
+ */
+void* memdebug_malloc(size_t bytes, const char* fname, size_t fline);
+
+/**
+ * @todo FIXME
+ */
+void memdebug_free(void* ptr);
+
+/**
+ * Imprime una DLList en un archivo.
+ *
+ * \param list DLList a imprimir.
+ * \param fh Puntero al archivo a escribir.
+ */
+void memdebug_list_print(FILE* fp);
+
+/**
+ * @todo FIXME
+ * Imprime la lista de memoria no liberada, la libera y borra la lista interna.
+ */
+void memdebug_end(void);
+
+#endif /* MEMDEBUG_H */
--- /dev/null
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=1 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 20:08:45 ART 2003
+ *
+ * $Id$
+ */
+
+/** \file
+ *
+ * Este es el archivo a incluir si se quieren usar las funciones personalizadas
+ * de malloc() y free().
+ */
+
+#ifndef MEMDEBUG_DEBUGGER_H
+#define MEMDEBUG_DEBUGGER_H
+
+#include "memdebug.h"
+
+#ifdef malloc
+#undef malloc
+#endif
+
+#ifdef free
+#undef free
+#endif
+
+/**
+ * Malloc personalizado.
+ * \see memdebug_malloc()
+ */
+#define malloc(b) memdebug_malloc(b, __FILE__, __LINE__)
+
+/**
+ * Free personalizado.
+ * \see memdebug_free()
+ */
+#define free(p) memdebug_free(p)
+
+#endif /* MEMDEBUG_DEBUGGER_H */
--- /dev/null
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 18:24:31 ART 2003
+ *
+ * $Id$
+ */
+
+/** \file
+ *
+ * Hace chequeos para probar el memdebugger.
+ */
+
+/* Para utilizar printf() */
+#include <stdio.h>
+/* Para utilizar EXIT_SUCCES */
+#include <stdlib.h>
+/* Para utilizar assert() */
+#include <assert.h>
+
+/* Para llamar al malloc() y free() personalizados. */
+#include "memdebug_debugger.h"
+
+/**
+ * Programa para probar el memdebug.
+ *
+ * \return EXIT_SUCCESS o código de error devuelto por abort() si hubo un
+ * error.
+ */
+int main(void) {
+ /* Declaración de variables. */
+ void* ptr1 = malloc(1000);
+ void* ptr2 = malloc(1000);
+ void* ptr3 = malloc(1000);
+
+ memdebug_list_print(stderr);
+
+ fprintf(stderr, "\n");
+
+ free(ptr1);
+ free(ptr2);
+ free(ptr3);
+
+ memdebug_end();
+
+ return EXIT_SUCCESS;
+}
--- /dev/null
+/* vim: set et sts=4 sw=4 fdm=indent fdl=1 fdn=0 fo+=t tw=80:
+ *
+ * Taller de Programación (75.42).
+ *
+ * Ejercicio Número 2:
+ * Programa calculadora.
+ *
+ * Copyleft 2003 - Leandro Lucarella <llucare@fi.uba.ar>
+ * Puede copiar, modificar y distribuir este programa bajo los términos de
+ * la licencia GPL (http://www.gnu.org/).
+ *
+ * Creado: sáb ago 30 20:08:45 ART 2003
+ *
+ * $Id$
+ */
+
+#include "meminfo.h"
+#include <stdlib.h>
+#include <string.h>
+
+MemInfo* MemInfo_new(void* ptr, size_t bytes, const char* fname, size_t fline) {
+ /* Aloco memoria. */
+ MemInfo* mi = malloc(sizeof(MemInfo));
+ /* Si la obtuve, inicializo con los datos y la hora actual. */
+ if (mi) {
+ mi->pointer = ptr;
+ mi->bytes = bytes;
+ mi->time = time(NULL);
+ mi->fileline = fline;
+ /* Reservo memoria para hacer la copia del nombre del archivo. */
+ mi->filename = (char*)malloc(strlen(fname));
+ /* Copio el nombre del archivo. */
+ strcpy(mi->filename, fname);
+ }
+ /* Devuelvo el nuevo puntero. */
+ return mi;
+}
+
+void MemInfo_delete(MemInfo* mi) {
+ /* Libero primero la memoria del nombre del archivo. */
+ free(mi->filename);
+ /* Libero la memoria del MemInfo. */
+ free(mi);
+}
+
#ifndef MEMINFO_H
#define MEMINFO_H
+#include <time.h>
+
/**
- * Nodo de la lista.
+ * Información sobre la memoria.
*/
typedef struct {
+ /** Puntero a la memoria reservada. */
void* pointer;
+ /** Cantidad de bytes reservados. */
size_t bytes;
+ /** Fecha en la que se reservó. */
time_t time;
+ /** Nombre del archivo de donde se reservó. */
char* filename;
+ /** Línea en la que se reservó. */
size_t fileline;
} MemInfo;
-MemInfo* MemInfo_new(void* ptr, size_t bytes, char* fname, size_t fline) {
- /* Aloco memoria. */
- MemInfo* mi = (MemInfo*)malloc(sizeof(MemInfo));
- /* Si la obtuve, inicializo con los datos y la hora actual. */
- if (mi) {
- mi->pointer = ptr;
- mi->bytes = bytes;
- mi->time = time();
- mi->filename = fname;
- mi->fileline = fline;
- }
- /* Devuelvo el nuevo puntero. */
- return mi;
-}
+/**
+ * Crea un nuevo MemInfo.
+ *
+ * \param ptr Puntero a un área de memoria.
+ * \param bytes Cantidad de bytes reservados.
+ * \param fname Nombre del archivo de donde se reservó.
+ * \param fline Línea en donde se reservó.
+ *
+ * \return Puntero al nuevo MemInfo o NULL si no hay espacio en la memoria.
+ */
+MemInfo* MemInfo_new(void* ptr, size_t bytes, const char* fname, size_t fline);
+
+/**
+ * Elimina un MemInfo.
+ *
+ * \param mi MemInfo a eliminar.
+ */
+void MemInfo_delete(MemInfo* mi);
#endif /* MEMINFO_H */