[net.unix] malloc with size keeping

allbery@ncoast.UUCP (Brandon Allbery) (06/22/86)

Expires:

Quoted from <2081@umcp-cs.UUCP> ["Re: get size of malloc'd object"], by chris@umcp-cs.UUCP...
+---------------
| 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:
+---------------

Lots of code excluded.

The original response had the right idea, but not portable.  Here's *my* way
(Change char * to void * if you have it:  mine's a broken PCC, so void is
blocked out):

char *mycalloc(count, size)
unsigned count, size; {
	char *block;
	int inx, off;
	
	inx = (sizeof (unsigned long) + sizeof (char *)) / size;
	off = size - sizeof (unsigned long) - sizeof (char *);
	if (inx == 0)
		inx++;
	if (off < 0)
		off += sizeof (unsigned long) + sizeof (char *);
	if ((block = calloc(count + inx, size)) == (char *) 0)
		return (char *) 0;
	*((char *) (block + off)) = block;
	*((unsigned long *) (block + off + sizeof (char *))) = count * size;
	return block + size;
}

myfree(block)
char *block; {
	return free(block - sizeof (unsigned long) - sizeof (char *));
}

unsigned mysize(block)
char *block; {
	return *((unsigned long *) block - sizeof (unsigned long));
}

This code uses the fact that a pointer may be stored without loss of precision
in some integer value; I assume that (unsigned long) is in fact the longest
integer available.  Except where a sign is stored separately, this will be
true.  (And in the latter case, the sign can't be used to store a number, so
even then it should hold.)  It also uses the fact that calloc() returns
storage aligned to any boundary, although it assumes that the C compiler also
forces struct sizes to be aligned to the size of the largest integer.

I don't worry about porting to unusual architectures, anyway:  if I write a
program that needs this kind of stuff, it's going to be even more incompatible
in other areas...

--Brandon
-- 
ihnp4!sun!cwruecmp!ncoast!allbery ncoast!allbery@Case.CSNET ncoast!tdi2!brandon
(ncoast!tdi2!root for business) 6615 Center St. #A1-105, Mentor, OH 44060-4101
Phone: +01 216 974 9210      CIS 74106,1032      MCI MAIL BALLBERY (part-time)