Ian said:
I'd offer another alternative that was pointed out to me in this thread:
p = malloc(s);
if(!p && s!=0)
failure().
The whole point of xmalloc() is that it either succeeds or aborts execution.
Now, since malloc(0) may or may not return NULL, that alone can't be taken
as indicator for failure in that corner case.
However, I think the agreed-on semantics of xmalloc are that you can
access 's' bytes starting at the returned pointer. Now, if 's' is zero, the
actual value that is returned doesn't matter[1], because effectively you
can only access zero bytes starting at that address. Using this allows
pretty uniform code for allocating arrays, no matter what their size is.
Since xmalloc checks against allocation failure and a zero size implicitly
guards you (provided proper use) against accessing this empty array, it
doesn't matter if you return NULL or some dummy value or change the
allocation size to one.
In that light, I'd even say that xmalloc should start like this:
if(s==0)
return NULL;
void* p=malloc(s);
...
The simple rationale is that dynamic allocations are typically expensive, so
avoiding them is worthwhile.
There is one caveat though: IIRC, quite a few implementations choke on
free(NULL), even more than those that choke on malloc(0). This might have
to be taken into account when porting to other platforms. It might be
easiest to change xmalloc() to always return at least one byte there.
Otherwise, you either have to check before calling free() or provide an
additional xfree() which behaves correctly.
The only case I can imagine this to fail is this kind of code:
// old version
p = malloc(s);
if(!p)
return ENOMEM;
// new version
p = xmalloc(s);
assert(p);// make sure xmalloc works
Both versions are in fact broken and their misbehaviour is not an indicator
of a broken xmalloc() implementation. The problem is that they both don't
take the weird malloc(0) behaviour into account. The correct code is this:
// old version
p = malloc(s);
if(!p && s!=0)
return ENOMEM;
// new version
p = xmalloc(s);
assert(p || s==0);// make sure xmalloc works
In my eyes, the assert() should be removed altogether, it only serves to
further clutter the code. Rather, I'd move the assert() into the
implementation of xmalloc().
Uli
[1] I'm aware of the fact that doing anything with uninitialised (random)
pointers is undefined.