mem.c
来自「国外网站上的一些精典的C程序」· C语言 代码 · 共 681 行
C
681 行
/*** This is a copyrighted work which is functionally identical to work** originally published in Micro Cornucopia magazine (issue #52, March-April,** 1990) and is freely licensed by the author, Walter Bright, for any use.*//*_ mem.c Fri Jan 26 1990 Modified by: Walter Bright *//* $Header: /proj/products/merlin/port/RCS/mem.c,v 1.19 89/10/20 14:36:02 bright Exp Locker: bright $ *//* Memory management package */#if defined(VAX11C)#define __FILE__ "mem.c"#endif#include <stdio.h>#include <stdlib.h>#include <io.h>#ifndef MEM_H#include "mem.h"#endif#ifndef assert#include <assert.h>#endif#if defined(_MSC_VER)#include <dos.h>#endif#if !defined(VAX11C)#ifdef BSDUNIX#include <strings.h>#else#include <string.h>#endif#elseextern char *strcpy(),*memcpy();extern int strlen();#endif /* VAX11C */int mem_inited = 0; /* != 0 if initialized */static int mem_behavior = MEM_ABORTMSG;static int (*fp)() = (int (*)())NULL; /* out-of-memory handler */static int mem_count; /* # of allocs that haven't been free'd */static int mem_scount; /* # of sallocs that haven't been free'd */static int near mem_exception(); /* called when out of memory *//* Determine where to send error messages */#if defined(MSDOS) || defined(__MSDOS__)#define ferr stdout /* stderr can't be redirected with MS-DOS */#else#define ferr stderr#endif/*******************************/void mem_setexception(flag,handler_fp)#if defined(__cplusplus) && __cplusplusenum MEM_E flag;#elseint flag;#endifint (*handler_fp)();{ mem_behavior = flag; fp = (mem_behavior == MEM_CALLFP) ? handler_fp : 0;#if defined(MEM_DEBUG) && MEM_DEBUG assert(0 <= flag && flag <= MEM_RETRY);#endif}/************************* * This is called when we're out of memory. * Returns: * 1: try again to allocate the memory * 0: give up and return NULL */static int near mem_exception(){ int behavior; behavior = mem_behavior; while (1) { switch (behavior) { case MEM_ABORTMSG:#if defined(MSDOS) || defined(__MSDOS__) || defined(__OS2__) /* Avoid linking in buffered I/O */ { static char msg[] = "Fatal error: out of memory\r\n"; write(1,msg,sizeof(msg) - 1); }#else fputs("Fatal error: out of memory\n",ferr);#endif /* FALL-THROUGH */ case MEM_ABORT: exit(EXIT_FAILURE); /* NOTREACHED */ case MEM_CALLFP: assert(fp); behavior = (*fp)(); break; case MEM_RETNULL: return 0; case MEM_RETRY: return 1; default: assert(0); } }}/****************************/#if defined(MEM_DEBUG) && MEM_DEBUG#undef mem_strdupchar *mem_strdup(s)const char *s;{ return mem_strdup_debug(s,__FILE__,__LINE__);}char *mem_strdup_debug(s,file,line)char *file;const char *s;int line;{ char *p; p = s ? (char *) mem_malloc_debug((unsigned) strlen(s) + 1,file,line) : NULL; return p ? strcpy(p,s) : p;}#elsechar *mem_strdup(s)const char *s;{ char *p; p = s ? (char *) mem_malloc((unsigned) strlen(s) + 1) : NULL; return p ? strcpy(p,s) : p;}#endif /* MEM_DEBUG */#ifdef MEM_DEBUGstatic long mem_maxalloc; /* max # of bytes allocated */static long mem_numalloc; /* current # of bytes allocated */#define BEFOREVAL 0x12345678 /* value to detect underrun */#define AFTERVAL 0x87654321 /* value to detect overrun */#if SUN || SUN386static long afterval = AFTERVAL; /* so we can do &afterval */#endif/* The following should be selected to give maximum probability that *//* pointers loaded with these values will cause an obvious crash. On *//* Unix machines, a large value will cause a segment fault. *//* MALLOCVAL is the value to set malloc'd data to. */#if MSDOS || __MSDOS__ || __OS2__#define BADVAL 0xFF#define MALLOCVAL 0xEE#else#define BADVAL 0x7A#define MALLOCVAL 0xEE#endif/* Disable mapping macros */#undef mem_malloc#undef mem_calloc#undef mem_realloc#undef mem_free/* Create a list of all alloc'ed pointers, retaining info about where *//* each alloc came from. This is a real memory and speed hog, but who *//* cares when you've got obscure pointer bugs. */static struct mem_debug{ struct mh { struct mem_debug *Mnext; /* next in list */ struct mem_debug *Mprev; /* previous value in list */ char *Mfile; /* filename of where allocated */ int Mline; /* line number of where allocated */ unsigned Mnbytes; /* size of the allocation */ long Mbeforeval; /* detect underrun of data */ } m; char data[1]; /* the data actually allocated */} mem_alloclist ={ { (struct mem_debug *) NULL, (struct mem_debug *) NULL, "noname", 11111, 0, BEFOREVAL }, AFTERVAL};/* Convert from a void *to a mem_debug struct. */#define mem_ptrtodl(p) ((struct mem_debug *) ((char *)p - sizeof(struct mh)))/* Convert from a mem_debug struct to a mem_ptr. */#define mem_dltoptr(dl) ((void *) &((dl)->data[0]))#define next m.Mnext#define prev m.Mprev#define file m.Mfile#define line m.Mline#define nbytes m.Mnbytes#define beforeval m.Mbeforeval/***************************** * Set new value of file,line */void mem_setnewfileline(ptr,fil,lin)void *ptr;char *fil;int lin;{ struct mem_debug *dl; dl = mem_ptrtodl(ptr); dl->file = fil; dl->line = lin;}/**************************** * Print out struct mem_debug. */static void near mem_printdl(dl)struct mem_debug *dl;{#if LPTR fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%lx\n", dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));#else fprintf(ferr,"alloc'd from file '%s' line %d nbytes %d ptr x%x\n", dl->file,dl->line,dl->nbytes,mem_dltoptr(dl));#endif}/**************************** * Print out file and line number. */static void near mem_fillin(fil,lin)char *fil;int lin;{ fprintf(ferr,"File '%s' line %d\n",fil,lin); fflush(ferr);}/**************************** * If MEM_DEBUG is not on for some modules, these routines will get * called. */void *mem_calloc(u)unsigned u;{ return mem_calloc_debug(u,__FILE__,__LINE__);}void *mem_malloc(u)unsigned u;{ return mem_malloc_debug(u,__FILE__,__LINE__);}void *mem_realloc(p,u)void *p;unsigned u;{ return mem_realloc_debug(p,u,__FILE__,__LINE__);}void mem_free(p)void *p;{ mem_free_debug(p,__FILE__,__LINE__);} /**************************/void mem_freefp(p)void *p;{ mem_free(p);}/*********************** * Debug versions of mem_calloc(), mem_free() and mem_realloc(). */void *mem_malloc_debug(n,fil,lin)unsigned n;char *fil;int lin;{ void *p; p = mem_calloc_debug(n,fil,lin); if (p) memset(p,MALLOCVAL,n); return p;}void *mem_calloc_debug(n,fil,lin)unsigned n;char *fil;int lin;{ struct mem_debug *dl; do dl = (struct mem_debug *) calloc(sizeof(*dl) + n + sizeof(AFTERVAL) - 1,1); while (dl == NULL && mem_exception()); if (dl == NULL) {#if 0 printf("Insufficient memory for alloc of %d at ",n); mem_fillin(fil,lin); printf("Max allocated was: %ld\n",mem_maxalloc);#endif return NULL; } dl->file = fil; dl->line = lin; dl->nbytes = n; dl->beforeval = BEFOREVAL;#if SUN || SUN386 /* bus error if we store a long at an odd address */ memcpy(&(dl->data[n]),&afterval,sizeof(AFTERVAL));#else *(long *) &(dl->data[n]) = AFTERVAL;#endif /* Add dl to start of allocation list */ dl->next = mem_alloclist.next; dl->prev = &mem_alloclist; mem_alloclist.next = dl; if (dl->next != NULL) dl->next->prev = dl; mem_count++; mem_numalloc += n; if (mem_numalloc > mem_maxalloc) mem_maxalloc = mem_numalloc; return mem_dltoptr(dl);}void mem_free_debug(ptr,fil,lin)void *ptr;char *fil;int lin;{ struct mem_debug *dl; if (ptr == NULL) return;#if 0 { fprintf(ferr,"Freeing NULL pointer at "); goto err; }#endif if (mem_count <= 0) { fprintf(ferr,"More frees than allocs at "); goto err; } dl = mem_ptrtodl(ptr); if (dl->beforeval != BEFOREVAL) {#if LPTR fprintf(ferr,"Pointer x%lx underrun\n",ptr);#else fprintf(ferr,"Pointer x%x underrun\n",ptr);#endif goto err2; }#if SUN || SUN386 /* Bus error if we read a long from an odd address */ if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)#else if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)#endif {#if LPTR fprintf(ferr,"Pointer x%lx overrun\n",ptr);#else fprintf(ferr,"Pointer x%x overrun\n",ptr);#endif goto err2; } mem_numalloc -= dl->nbytes; if (mem_numalloc < 0) { fprintf(ferr,"error: mem_numalloc = %ld, dl->nbytes = %d\n", mem_numalloc,dl->nbytes); goto err2; } /* Remove dl from linked list */ if (dl->prev) dl->prev->next = dl->next; if (dl->next) dl->next->prev = dl->prev; /* Stomp on the freed storage to help detect references */ /* after the storage was freed. */ memset((void *) dl,BADVAL,sizeof(*dl) + dl->nbytes); mem_count--; /* Some compilers can detect errors in the heap. */#if defined(DLC) { int i; i = free(dl); assert(i == 0); }#else free((void *) dl);#endif return;err2: mem_printdl(dl);err: fprintf(ferr,"free'd from "); mem_fillin(fil,lin); assert(0); /* NOTREACHED */}/******************* * Debug version of mem_realloc(). */void *mem_realloc_debug(oldp,n,fil,lin)void *oldp;unsigned n;char *fil;int lin;{ void *p; struct mem_debug *dl; if (n == 0) { mem_free_debug(oldp,fil,lin); p = NULL; } else if (oldp == NULL) p = mem_malloc_debug(n,fil,lin); else { p = mem_malloc_debug(n,fil,lin); if (p != NULL) { dl = mem_ptrtodl(oldp); if (dl->nbytes < n) n = dl->nbytes; memcpy(p,oldp,n); mem_free_debug(oldp,fil,lin); } } return p;}/***************************/void mem_check(){ register struct mem_debug *dl; for (dl = mem_alloclist.next; dl != NULL; dl = dl->next) mem_checkptr(mem_dltoptr(dl));}/***************************/void mem_checkptr(p)register void *p;{ register struct mem_debug *dl; for (dl = mem_alloclist.next; dl != NULL; dl = dl->next) { if (p >= (void *) &(dl->data[0]) && p < (void *)((char *)dl + sizeof(struct mem_debug)-1 + dl->nbytes)) goto L1; } assert(0);L1: dl = mem_ptrtodl(p); if (dl->beforeval != BEFOREVAL) {#if LPTR fprintf(ferr,"Pointer x%lx underrun\n",p);#else fprintf(ferr,"Pointer x%x underrun\n",p);#endif goto err2; }#if SUN || SUN386 /* Bus error if we read a long from an odd address */ if (memcmp(&dl->data[dl->nbytes],&afterval,sizeof(AFTERVAL)) != 0)#else if (*(long *) &dl->data[dl->nbytes] != AFTERVAL)#endif {#if LPTR fprintf(ferr,"Pointer x%lx overrun\n",p);#else fprintf(ferr,"Pointer x%x overrun\n",p);#endif goto err2; } return;err2: mem_printdl(dl); assert(0);}#else/***************************/void *mem_malloc(numbytes)unsigned numbytes;{ void *p; if (numbytes == 0) return NULL; while (1) { p = malloc(numbytes); if (p == NULL) { if (mem_exception()) continue; } else mem_count++; break; } /*printf("malloc(%d) = x%lx\n",numbytes,p);*/ return p;}/***************************/void *mem_calloc(numbytes)unsigned numbytes;{ void *p; if (numbytes == 0) return NULL; while (1) { p = calloc(numbytes,1); if (p == NULL) { if (mem_exception()) continue; } else mem_count++; break; } /*printf("calloc(%d) = x%lx\n",numbytes,p);*/ return p;}/***************************/void *mem_realloc(oldmem_ptr,newnumbytes)void *oldmem_ptr;unsigned newnumbytes;{ void *p; if (oldmem_ptr == NULL) p = mem_malloc(newnumbytes); else if (newnumbytes == 0) { mem_free(oldmem_ptr); p = NULL; } else { do p = realloc(oldmem_ptr,newnumbytes); while (p == NULL && mem_exception()); } /*printf("realloc(x%lx,%d) = x%lx\n",oldmem_ptr,newnumbytes,p);*/ return p;}/***************************/void mem_free(ptr)void *ptr;{ /*printf("free(x%lx)\n",ptr);*/ if (ptr != NULL) { assert(mem_count > 0); mem_count--;#if defined(DLC) && DLC { int i; i = free(ptr); assert(i == 0); }#else free(ptr);#endif }}#endif /* MEM_DEBUG *//***************************/void mem_init(){ if (mem_inited == 0) { mem_count = 0;#if defined(MEM_DEBUG) && MEM_DEBUG mem_numalloc = 0; mem_maxalloc = 0; mem_alloclist.next = NULL;#endif#if defined(__ZTC__) || defined(__SC__) /* Necessary if mem_sfree() calls free() before any */ /* calls to malloc(). */ free(malloc(1)); /* initialize storage allocator */#endif mem_inited++; }}/***************************/void mem_term(){ if (mem_inited) {#if defined(MEM_DEBUG) && MEM_DEBUG register struct mem_debug *dl; for (dl = mem_alloclist.next; dl; dl = dl->next) { fprintf(ferr,"Unfreed pointer: "); mem_printdl(dl); }#if 0 fprintf(ferr,"Max amount ever allocated == %ld bytes\n", mem_maxalloc);#endif#else if (mem_count) fprintf(ferr,"%d unfreed items\n",mem_count); if (mem_scount) fprintf(ferr,"%d unfreed s items\n",mem_scount);#endif /* MEM_DEBUG */ assert(mem_count == 0 && mem_scount == 0); mem_inited = 0; }}#undef next#undef prev#undef file#undef line#undef nbytes#undef beforeval
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?