[net.lang.c] malloc

eklhad@ihnet.UUCP (K. A. Dahlke) (09/07/84)

I once had to malloc() a 3-dimensional table.
The code was not proprietary, so here is a fragment.

mktbl(){
unsigned short (*freq)[ASIZE][ASIZE];

/* malloc a 3-dimensional table of triple frequencies */
freq = (unsigned short ***)
malloc(sizeof(unsigned short)*ASIZE*ASIZE*ASIZE);
for(i=0;i<ASIZE*ASIZE*ASIZE;++i)
freq[0][0][i]=0;
...
++freq[c1][c2][c3];
...
}

When I asked a structured programmer how to solve this malloc problem,
the answer was immediate and predictable.
"put the array in a structure."
struct FOO {
unsigned short freq[ASIZE][ASIZE][ASIZE];
} *foo;
mktbl(){
/* malloc a 3-dimensional table of triple frequencies */
foo = (struct FOO*)
malloc(sizeof(unsigned short)*ASIZE*ASIZE*ASIZE);
for(i=0;i<ASIZE*ASIZE*ASIZE;++i)
foo->freq[0][0][i]=0;
...
++(foo->freq[c1][c2][c3]);
...
}

The foo-> stuff is annoying to type,
but the structures are simpler to understand, and more portable.
-- 

Karl Dahlke    ihnp4!ihnet!eklhad

gary@cirl.UUCP (Gary Girzon) (09/03/85)

I would appreciate some help on the following problem. When using
malloc() in C ( runing 4.2 bsd ), I cannot allocate more than roughly
4 megabytes. This seems to be limited by our core size. I would 
like to know whether this limit can be extended to handle virtual
memory on the VAX. Also, any information on how the C compiler deals with
virtual memory (if at all) would be appreciated.

					Gary Girzon

UUCP: ihnp4!think!cirl!gary

anton@ucbvax.ARPA (Jeff Anton) (09/05/85)

In article <203@cirl.UUCP> gary@cirl.UUCP (Gary Girzon) writes:
>I would appreciate some help on the following problem. When using
>malloc() in C ( runing 4.2 bsd ), I cannot allocate more than roughly
>4 megabytes. This seems to be limited by our core size. I would 
>like to know whether this limit can be extended to handle virtual
>memory on the VAX. Also, any information on how the C compiler deals with
>virtual memory (if at all) would be appreciated.

The C compiler does not bother with VMem knowledge except for its
own use.  You are probably encountering a limit imposed by malloc.
I'd suggest you try useing sbrk(2).  I recently needed a 6 Mbytes for
raster plotting and malloc complained but sbrk worked fine.  I don't
suggest running jobs that exceed system core size, but sometimes
we don't have any way around the matter.  You might also try out the
'limit' command in csh.  Check out sbrk(2), setrusage(2), and the
'obsolete' vadvise(2).  (vadvise is hidden in 4.2 for use by lisp,
and some CAD tools, and maybe apl; it might be named Ovadvise)
-- 
C knows no bounds.
					Jeff Anton
					U.C.Berkeley
					Ingres Group
					ucbvax!anton
					anton@BERKELEY.EDU

chris@umcp-cs.UUCP (Chris Torek) (09/06/85)

The 4.2 malloc rounds each request up to the nearest power of two
(sounds space inefficient [and is], but very time efficient; see
Korn's paper in Proceedings Winter '85 Usenix).  Since as distributed
4.2 has a per-process VM limit of 6M, you cannot allocate more than
4M with malloc.  (Of course if you raise the VM limits you can get
as much space as you like, provided you have lots of paging space.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

jon@CIT-VAX.ARPA (Jonathan P. Leech) (09/07/85)

> From: Chris Torek
> ... Since as distributed 4.2 has a per-process VM limit of 6M, you
> cannot allocate more than 4M with malloc.

	I don't understand how this works. Suppose I allocate two
blocks, one 4M (2^22 bytes) and one 2M (2^21). These are both powers
of two, and I get 6M total. Or does malloc round it up by a 
factor of two if you are unlucky enough to request a power of two (not
counting overhead in the free list, of course)? 
	-- Jon Leech (jon@cit-vax.arpa)
	__@/

chris%umcp-cs.uucp@BRL.ARPA (Chris Torek) (09/08/85)

> From: jon@cit-vax (Jonathan P. Leech)

>> From: Chris Torek
>> ... Since as distributed 4.2 has a per-process VM limit of 6M, you
>> cannot allocate more than 4M with malloc.

> I don't understand how this works. Suppose I allocate two blocks,
> one 4M (2^22 bytes) and one 2M (2^21). These are both powers of
> two, and I get 6M total.  Or does malloc round it up by a factor
> of two if you are unlucky enough to request a power of two . . . .

Sorry, I was not specific enough.  You can allocate one 4M chunk
and one 2M chunk; you cannot allocate one 6M chunk.

The size you hand to malloc has (in our C library at any rate) 4
added to it, then the result is brought up to the nearest power of
two.  So if you give it ((1 << 22) - 4) you will get a 4M chunk;
one more byte and malloc will require an 8M chunk.  (If you compile
malloc with range checking the overhead grows to 12 bytes.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

jpl@allegra.UUCP (John P. Linderman) (09/10/85)

> The size you hand to malloc has (in our C library at any rate) 4
> added to it, then the result is brought up to the nearest power of
> two.  So if you give it ((1 << 22) - 4) you will get a 4M chunk;
> one more byte and malloc will require an 8M chunk.
> -- 
> In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)

Chris is right (as usual) about the 4.2 malloc being about 50%
efficient when allocating blocks whose size is a power of 2,
(like the buffers that stdio will allocate).  Another ``gotcha''
to beware of is that space, once allocated, is never broken
into smaller pieces.  For example, if I allocate a 4 meg
temporary workspace, free it, then allocate a 2 meg area,
malloc will not reuse the freed space, it will try for a new
area, and, thanks to the aforementioned quirks, it will fail
with the standard 6 meg per-process limit.  Dunno if this is
fixed under 4.3.  One can hope, but I wouldn't bet the farm.

John P. Linderman  Space Cadet  allegra!jpl

chris@umcp-cs.UUCP (Chris Torek) (09/11/85)

> ...  Another ``gotcha'' to beware of is that space, once allocated,
> is never broken into smaller pieces. [...] Dunno if this is fixed
> under 4.3.
>
> John P. Linderman  Space Cadet  allegra!jpl

I doubt it will be; it has not yet been done.  It might create yet
another ``gotcha'', however, as coalescing smaller blocks is fairly
tricky.

By the way, I quote from my own version of the CalTech malloc which
I use in my Emacs:

 /* If there are no blocks of the appropriate size, go get some */
 /* COULD SPLIT UP A LARGER BLOCK HERE ... ACT */
    if (nextf[nunits] == NULL)
	morecore (nunits);

I put that comment in when I rewrote most of the code; the RCS logs
say that was 84/06/29---more than a year ago.
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 4251)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@maryland

kwh@bentley.UUCP (KW Heuer) (05/14/86)

In article <866@ttrdc.UUCP> ttrdc!levy (Dan Levy) writes:
>Y'know--while I'm thinking about it, why IS malloc() set up to return a
>(char *) pointer at all, if that IS inviting a potential (or at least to
>lint's little mind) pointer alignment problem?  Since malloc() is supposed
>to return a maximally aligned pointer, seems to me that it should have
>been set up to return a (double *).  Yes, yes, before flames of misunder-
>standing start, I _KNOW_ that the convention for malloc() is to return
>a (char *) and that it returns a maximally aligned pointer just the same
>because of the way it has been written.  It just seems that the methodology
>was back-a**wards, that at least returning a (double *) would indicate an
>implicit promise to the user (and to lint-like checking) that the return
>value WAS maximally aligned.  The only problem I could see with this kind
>of scheme is that some systems might not support double.  But that could
>be gotten around by #defining a malloc_t type that would represent the
>maximally aligned data type of the machine at hand.

This is what I started to mention once before, and picked up a lot of "no,
you don't understand how it works" messages (sigh).  I saw the need for a
"ALIGN *" datatype, and was hoping "void *" would be it.  (Nope, just a
useless synonym for "char *").  The idea would be that, just as it's always
legal to cast any pointer into a "char *", it would be legal to cast *from*
"ALIGN *" to any pointer.  Then lint would shut up about malloc()!

Also, having malloc() return a real "ALIGN *" would be convenient for word-
addressible machines where "char *" requires extra bits.

Btw, if I really want to reduce the signal/noise ratio in lint, I use
#if lint
extern char       *cmalloc();
extern int        *imalloc();
extern struct foo *fmalloc();
...
#else
extern char *malloc();
#define cmalloc(n) ((char       *)malloc((n)*sizeof(char))
#define imalloc(n) ((int        *)malloc((n)*sizeof(int))
#define fmalloc(n) ((struct foo *)malloc((n)*sizeof(struct foo))
...
#endif

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint

jon@cit-vax.Caltech.Edu (Jonathan P. Leech) (05/14/86)

Summary:
Expires:
Sender:
Followup-To:
Distribution:

Organization : California Institute of Technology
Keywords:

In article <815@bentley.UUCP> kwh@bentley.UUCP (KW Heuer) writes:
>
>This is what I started to mention once before, and picked up a lot of "no,
>you don't understand how it works" messages (sigh).  I saw the need for a
>"ALIGN *" datatype, and was hoping "void *" would be it.  (Nope, just a
>useless synonym for "char *").  The idea would be that, just as it's always
>legal to cast any pointer into a "char *", it would be legal to cast *from*
>"ALIGN *" to any pointer.  Then lint would shut up about malloc()!
>

    I don't think 'void *' is useless. What do you  do	on  a  machine
where it's NOT 'always legal to cast any pointer into a "char *"'?   I
find 'void *' most wonderful and useful in C++.
-- 
    Jon Leech (jon@csvax.caltech.edu || ...seismo!cit-vax!jon)
    Caltech Computer Science Graphics Group
    __@/

guy@sun.uucp (Guy Harris) (05/14/86)

> I saw the need for a "ALIGN *" datatype, and was hoping "void *" would
> be it.  (Nope, just a useless synonym for "char *").  The idea would
> be that, just as it's always legal to cast any pointer into a "char *",
> it would be legal to cast *from* "ALIGN *" to any pointer.  Then lint
> would shut up about malloc()!

No, you just don't understand how it works.  From the August 11, 1985 C
standard draft:

	C.2.2.3 Pointers

	   A pointer to "void" may be converted to a pointer to an
	object of any type.  A pointer to an object of any type may be
	converted to a pointer to "void" or to a pointer to an object
	of less strict alignment and back again without change.

Nowhere is it implied that "void *" is a synonym for "char *".  "lint"
should not give any complaints about conversions between pointers of other
types and pointers to "void" (this isn't stated in the C draft, but then
again it's not a description of "lint", it's a language standard).  As such,
it is not a synonym for "char *", since "lint" should (and does) complain
about conversions between "char *" and other pointers.  As the C draft
clearly states, it is legal to cast *from* "void *" to any pointer; as such,
if "malloc" is declared to return "void *", "lint" will shut up about it.

No, the language does not *guarantee* that a "void *" is properly aligned,
but there's no way for it to do so anyway.  Big deal.  The language couldn't
*guarantee* that an "ALIGN *" is properly aligned either - if you wrote
"malloc" in C (as all UNIX implementations I know of are written), you would
just have to trust that the implementation delivers a maximally-aligned
pointer.  As such, "ALIGN *" is just a useless synonym for "void *".

> Also, having malloc() return a real "ALIGN *" would be convenient for word-
> addressible machines where "char *" requires extra bits.

Maybe, but I'm not sure the added convenience of having "malloc" be able to
return a value of a type requiring fewer bits is sufficient to justify
adding another type to the language.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.arpa

ark@alice.UucP (Andrew Koenig) (05/15/86)

>    I don't think 'void *' is useless. What do you  do	on  a  machine
> where it's NOT 'always legal to cast any pointer into a "char *"'?

You don't implement C on it.

kwh@bentley.UUCP (KW Heuer) (05/16/86)

In article <479@cit-vax.Caltech.Edu> cit-vax!jon writes:
>    I don't think 'void *' is useless. What do you  do	on  a  machine
>where it's NOT 'always legal to cast any pointer into a "char *"'?

You get a compiler that works.  The proposed property of "void *" is
already guaranteed for "char *".  (Sorry, no K&R handy, can't quote it.)

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint

levy@ttrdc.UUCP (Daniel R. Levy) (05/19/86)

In article <5462@alice.uUCp>, ark@alice.UucP (Andrew Koenig) writes:
>>    I don't think 'void *' is useless. What do you  do	on  a  machine
>> where it's NOT 'always legal to cast any pointer into a "char *"'?
>
>You don't implement C on it.

Why not?  If a "char *" per se (the machine's idea of a byte address) doesn't
contain sufficient information to reconstruct another type of address from it, 
you could always have the compiler generate code to carry around enough extra
information with the C pointers to allow reconstruction of pointers to larger
data types.

Can anyone name such a machine which wouldn't be amenable to this?  I'm not
talking about machines that are hostile to unbridled pointers like the
Burroughs beasts (no hardware memory protection).  I'm talking about machines
whose byte and word addressing schemes have no relationship whatsoever.
-- 
 -------------------------------    Disclaimer:  The views contained herein are
|       dan levy | yvel nad      |  my own and are not at all those of my em-
|         an engihacker @        |  ployer or the administrator of any computer
| at&t computer systems division |  upon which I may hack.
|        skokie, illinois        |
 --------------------------------   Path: ..!{akgua,homxb,ihnp4,ltuxa,mvuxa,
						vax135}!ttrdc!levy

kwh@bentley.UUCP (KW Heuer) (05/19/86)

In article <3674@sun.uucp> sun!guy writes:
[bentley!kwh writes:]
>> I saw the need for a "ALIGN *" datatype, and was hoping "void *" would
>> be it.  (Nope, just a useless synonym for "char *").  The idea would
>> be that, just as it's always legal to cast any pointer into a "char *",
>> it would be legal to cast *from* "ALIGN *" to any pointer.  Then lint
>> would shut up about malloc()!
>
>No, you just don't understand how it works.  From the August 11, 1985 C
>standard draft:
>
>	C.2.2.3 Pointers
>
>	   A pointer to "void" may be converted to a pointer to an
>	object of any type.  A pointer to an object of any type may be
>	converted to a pointer to "void" or to a pointer to an object
>	of less strict alignment and back again without change.
>
>Nowhere is it implied that "void *" is a synonym for "char *".

Since sizeof(char) == 1 (I believe that's now a guaranteed rule rather than
merely "true in all known implementations", right?), it has the least strict
alignment.  Thus your last quoted sentence implies that "char *" can also
hold a pointer of any type, and restore it unchanged.  And to even attempt
to restore it means that "char *" must meet the first property as well.  So,
although not necessarily synonyms, they do have the same properties, except
that "char *" conversions usually require a cast to be acceptable.

>No, the language does not *guarantee* that a "void *" is properly aligned,
>but there's no way for it to do so anyway.  Big deal.  The language couldn't
>*guarantee* that an "ALIGN *" is properly aligned either...

What I had in mind was that "ALIGN *" would be a synonym for "int *" or
whatever happens to be the most restrictive pointer type.  The "guarantee"
would be as good as the "guarantee" on an "int *".

>> Also, having malloc() return a real "ALIGN *" would be convenient for word-
>> addressible machines where "char *" requires extra bits.
>
>Maybe, but I'm not sure the added convenience of having "malloc" be able to
>return a value of a type requiring fewer bits is sufficient to justify
>adding another type to the language.

Well, what *is* the justification for adding "void *" to the language?  To
allow people to shove pointers around without casts?  (Shudder!)  To make
lint shut up about malloc()?  Or just to distinguish "generic pointers" from
pointers that can be dereferenced?  (Could be done with a typedef.  So could
"void", but they put it in anyway.)

I do not strongly object to the addition of "void *", but I am worried about
it "hiding" errors.  (I'm one of those purists who thinks that programmers
*should* use casts to change types.)  Also, it's a misnomer; it has nothing
to do with "void".

Karl W. Z. Heuer (ihnp4!bentley!kwh), The Walking Lint

rbutterworth@watmath.UUCP (Ray Butterworth) (05/22/86)

> Well, what *is* the justification for adding "void *" to the language?  To
> allow people to shove pointers around without casts?  (Shudder!)  To make
> lint shut up about malloc()?  Or just to distinguish "generic pointers" from
> pointers that can be dereferenced?  (Could be done with a typedef.  So could
> "void", but they put it in anyway.)
> 
> I do not strongly object to the addition of "void *", but I am worried about
> its "hiding" errors.  (I'm one of those purists who thinks that programmers
> *should* use casts to change types.)  Also, it's a misnomer; it has nothing
> to do with "void".

When I first heard of (void*), I thought it was a wonderful idea.
malloc() and realloc() would return this type and it would be
guaranteed to be properly aligned and assignable to any other
type of pointer without complaint.  This much turned out to be true.

I also thought that casting anything into a (void*) would be a big
no-no.  Lint, and maybe even the compiler, would issue loud warnings
every time one tried to do this.  This wouldn't matter since normal
programs would never need to do it, and the warnings would only be
generated when malloc() and realloc() were compiled.  Unfortunately
this turned out to be false.

For some perverse reason that I have never been able to understand,
X3J11 decided that any pointer could be converted to (void*) without
complaint.  There was no need for this additional usage since the
standard also guarantees that any pointer may be correctly cast to
(char*).  It adds nothing useful and makes it much easier to code
undetectible errors.

(Lint complains too much about your code?  Don't worry, just change
all the pointers to void* and it will shut up.  (I assume you already
"#define CALL (void*)" and put CALL in front of all your function
calls so that you don't have to check any error statuses.)  Perhaps
lint should have an option which redirects all output to /dev/null?)

chris@umcp-cs.UUCP (Chris Torek) (05/24/86)

The real reason for `void *', which everyone seems to be missing,
is that it provides a generic pointer type.

Of course, if you need such a thing, you can usually get away with

	union all_possible_ptrs {
		char		*ifchar;
		unsigned char	*ifuchar;
		short		*ifshort;
		unsigned short	*ifushort;
		int		*ifint;
		unsigned int	*ifunit;
		long		*iflong;
		unsigned long	*ifulong;
		float		*iffloat;
		double		*ifdouble;
	};

but it is conceivable that this might be insufficent on a
machine with special structure pointers.  On such a machine,
this union might be (say) 30 bits wide, whereas a generic
pointer might be 34 bits.  Thus `void *'.

Besides, do you really *want* to use such a union?
-- 
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

guy@sun.UUCP (05/24/86)

> I also thought that casting anything into a (void*) would be a big
> no-no.  Lint, and maybe even the compiler, would issue loud warnings
> every time one tried to do this.

The key word here is "warnings".  The X3J11 standard doesn't say what
constructs may not give warnings; it merely states what is and isn't legal
C.  As long as the compiler produces code for it, X3J11 doesn't care how
many complaints it puts out.

Maybe C should be stricter about types (I think so), but it's too late for
that.

> This wouldn't matter since normal programs would never need to do it...

Well, err, umm, "void *" is also useful for declaring objects used by
several different modules, where each client of the object's implementation
wants to store some private data in the object, and you can't get away with
statically restricting the class of modules using this object.  Dennis
Ritchie's "streams" article in the BSTJ gives an example of this.  A "queue"
has pointers to "put" and "service" procedures, and a "void *" which
provides private storage for those procedures.  Replacing that "void *" with
a "struct tty *", or a union of similar structures, would be ridiculous.
Yes, you can't rely on the type system to check correctness.  (Maybe
something like Goedel's Incompleteness Theorem applies, where any type
system strong enough that all programs written using it are "correct" is
incomplete, in that there exist interesting and meaningful programs which
cannot be written within this type system?)

> For some perverse reason that I have never been able to understand,
> X3J11 decided that any pointer could be converted to (void*) without
> complaint.

No, they just decided that it could be so converted in a legal C program.
Appendix E.3 gives a list of warnings which many implementations might give;
the situations listed are all legal C, but may not be desirable C.

> (Lint complains too much about your code?  Don't worry, just change
> all the pointers to void* and it will shut up.  (I assume you already
> "#define CALL (void*)" and put CALL in front of all your function
> calls so that you don't have to check any error statuses.)  Perhaps
> lint should have an option which redirects all output to /dev/null?)

If you're worried about programmers trying to spoof "lint" you'd better find
some way of preventing them from hiding all dubious code inside "#ifdef
lint".  C is not guaranteed to work in an environment where you have to ride
herd on programmers.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.arpa

bright@dataioDataio.UUCP (Walter Bright) (05/27/86)

In article <3754@sun.uucp> guy@sun.uucp (Guy Harris) writes:
>> I also thought that casting anything into a (void*) would be a big
>> no-no.  Lint, and maybe even the compiler, would issue loud warnings
>> every time one tried to do this.
>> For some perverse reason that I have never been able to understand,
>> X3J11 decided that any pointer could be converted to (void*) without
>> complaint.

Ah, but if you have a function prototype such as:

	extern void free(void *);

and then try to free a pointer to a struct, you are implicitly casting
the struct pointer to a void *. Generating an error on this would
make void * fairly useless.

guy@sun.UUCP (05/28/86)

> In article <3754@sun.uucp> guy@sun.uucp (Guy Harris) writes:
> >> I also thought that casting anything into a (void*) would be a big
> >> no-no. ...

Guy Harris wrote nothing of the sort.  Karl W. Z. Heuer wrote that.  The "In
article..." crap is put there by *some* versions of "postnews", but not all.
(The version we run here doesn't put it there, for example.)  It is,
therefore, an unreliable indicator, and should probably be deleted before
sending out articles.
-- 
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.arpa

rbutterworth@watmath.UUCP (Ray Butterworth) (05/29/86)

> Ah, but if you have a function prototype such as:
> 	extern void free(void *);
> and then try to free a pointer to a struct, you are implicitly casting
> the struct pointer to a void *. Generating an error on this would
> make void * fairly useless.

But if I were king, free() wouldn't take a (void*).
Almost the only place (void*) would be used is by malloc().

There is a need for two special types of generic pointers:  one which
is guaranteed to be aligned and can be cast into any other pointer, and
one which has no such guarantee and can have any other pointer cast
into it.  (void*) clearly fits the former.  (char*) almost fits the
latter (perhaps a new (pointer) type should have been introduced).
X3J11 defeated the niceness of all this by extending their definition
of (void*) to fit both requirements.  I really don't understand why
they would do such a thing.  It gains nothing and loses a lot.

kwh@bentley.UUCP (KW Heuer) (05/30/86)

In article <3788@sun.uucp> guy@sun.UUCP (Guy Harris) writes:
>> In article <3754@sun.uucp> guy@sun.uucp (Guy Harris) writes:
>> >> I also thought that casting anything into a (void*) would be a big
>> >> no-no. ...
>
>Guy Harris wrote nothing of the sort.  Karl W. Z. Heuer wrote that.

Wrong squared.  It was watmath!rbutterworth who wrote it.

Karl W. Z. Heuer (ihnp4!bentley!kwh), the Walking Lint

ron@brl-sem.ARPA (Ron Natalie <ron>) (06/01/86)

In article <113@watmath.UUCP>, rbutterworth@watmath.UUCP (Ray Butterworth) writes:

> There is a need for two special types of generic pointers:  one which
> is guaranteed to be aligned and can be cast into any other pointer, and
> one which has no such guarantee and can have any other pointer cast
> into it.  (void*) clearly fits the former.  (char*) almost fits the
> latter (perhaps a new (pointer) type should have been introduced).
> X3J11 defeated the niceness of all this by extending their definition
> of (void*) to fit both requirements.  I really don't understand why
> they would do such a thing.  It gains nothing and loses a lot.

Eh?  "void *" is a pointer that is big enough to hold any other pointer.
It makes no attempt at alignment.  Nowhere in C is there any guarantees
on alignment.  You assign an unaligned char into an int pointer on some
machines it will work, some it won't be aligned right, and some will
generate bizarre pointers as a result.  It is a feature of MALLOC that
it never puts anything into that void* it returns that isn't aligned,
but that is extremely implentation dependant.

-Ron