Relay-Version: version B 2.10 5/3/83; site utzoo.UUCP Path: utzoo!watmath!clyde!burl!ulysses!allegra!princeton!caip!topaz!harvard!seismo!umcp-cs!chris From: chris@umcp-cs.UUCP (Chris Torek) Newsgroups: net.unix,net.unix-wizards,net.arch,net.lang.c Subject: Re: get size of malloc'd object Message-ID: <2081@umcp-cs.UUCP> Date: Wed, 18-Jun-86 15:12:43 EDT Article-I.D.: umcp-cs.2081 Posted: Wed Jun 18 15:12:43 1986 Date-Received: Sat, 21-Jun-86 07:25:05 EDT References: <165@daisy.UUCP> <334@valid.UUCP> <2206@peora.UUCP> Organization: Computer Sci. Dept, U of Maryland, College Park, MD Lines: 122 Xref: watmath net.unix:8258 net.unix-wizards:18497 net.arch:3511 net.lang.c:9496 In article <2206@peora.UUCP>, jer@peora.UUCP (J. Eric Roskos) writes: >... allocate a sizeof(int) worth of extra space, then store the >size of the thing you malloc'ed in the int at the front of the >allocated block, advance the pointer past the place where your >stored the size, and return that as the pointer to the block you >allocated. > >This approach is portable, simple, and easy to understand. Also >it doesn't require any assumptions about what kind of objects are >being allocated. Unfortunately, it is not necessarily portable. I can imagine a machine where `double' arguments must be aligned on an eight-byte boundary, but integers are only four bytes wide. In this case calling the new routine to allocate doubles would result in an odd-address-style trap when the returned value is used. What can be done is this: #include /* change all `char *'s to `void *'s in ANSI C */ struct mymem { struct mymem *m_next; /* linked list */ struct mymem *m_prev; /* doubly, for easy removal */ unsigned m_size; /* size of mem, in bytes */ char *m_mem; /* storage */ }; /* queue head */ static struct mymem m_base = { &m_base, &m_base }; extern char *malloc(); /* * Allocate some memory, remembering its size. */ char * myalloc(size) unsigned size; { register struct mymem *m; if ((m = (struct mymem *) malloc(sizeof (*m))) == NULL) return (NULL); if ((m->m_mem = malloc(size)) == NULL) { free((char *) m); return (NULL); } m->m_size = size; /* * Insert at head: change to tail if mem usage is more * `queueish' than `stackish'. */ m->m_next = m_base.m_next; m->m_prev = &m_base; m_base.m_next->m_prev = m; m_base.m_next = m; return (m->m_mem); } /* * Locate the queue element corresponding to the given memory * region. */ static struct mymem * myfind(mem) register char *mem; { register struct mymem *m = &m_base; while ((m = m->m_next) != &m_base) if (m->m_mem == mem) return (m); return (NULL); } /* * Free a region, and drop it from the queue. */ myfree(mem) char *mem; { register struct mymem *m = myfind(mem); if (m == NULL) { /* * Complain? Abort? Or what? * Change to suit local tastes... */ (void) fprintf(stderr, "myfree: invalid free\n"); (void) fflush(stderr); abort(); } /* remove from queue */ m->m_next->m_prev = m->m_prev; m->m_prev->m_next = m->m_next; /* and discard */ free(m->m_mem); free((char *) m); } unsigned mysize(mem) char *mem; { struct mymem *m; if ((m = myfind(mem)) == NULL) return (0); /* not allocated */ return (m->m_size); } This definitely *is* portable, if slow for large remembrance queues. Of course, malloc() knows all along how big the allocated region is (though the number it knows might be larger than the original request); so it is a shame to have to go through all this effort. -- In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516) UUCP: seismo!umcp-cs!chris CSNet: chris@umcp-cs ARPA: chris@mimsy.umd.edu