(no title)
amavect | 11 months ago
void *sane_realloc(void *ptr, size_t size)
{
if (size == 0) {
free(ptr);
return 0;
} else {
return realloc(ptr, size);
}
}
Unfortunately, when shrinking an array down to 0, you run into a complication. Detecting allocation failure now requires checking both size > 0 and sane_realloc returning 0. To simplify this further, just always allocate a non-zero size. void *saner_realloc(void *ptr, size_t size)
{
if (size == 0) {
size = 1;
}
return realloc(ptr, size);
}
kazinator|11 months ago
According to ISO C, size zero can behave like this:
and if malloc(0) allocates something, we have not achieved freeing.There are ways to implement malloc(0) such that it returns unique pointers, without allocating memory. Or at least not very much memory. For instance we can use the 64 bit space to have some range of (unmapped) virtual addresses where we allocate bytes, and use a compact bitmask (actually allocated somewhere) to keep track of them.
Such a scheme was described by Tim Rentsch in the Usenet newsgroup comp.lang.c.
If an implementation does such a thing, adjusting the size to 1 will defeat it; allocations of size 1 need real memory.
(I can't fathom the requirement why we need malloc(0) to be a source of unique values, and why someone would implement that as efficiently as possible, when it's implementation-defined behavior that portable programs cannot rely on. Why wouldn't you use some library module for unique, space-efficient pointers.)
I would never rely malloc(0) to obtain unique pointers at all, let alone pray that it is efficient for that purpose.
I'd be happy with a malloc(0) which returns, for instance, ((void *) -1) which can be hidden behind some #define symbol.
saner_realloc isn't realloc; it is our API, and we can make it do this:
Now, a null return always means failure. The shrink to zero, or allocate zero cases give us SANE_REALLOC_EMPTY which tests unequal to null, and we accept that value for growing or freeing.The caller can also pass in something returned by malloc(0) that is not equal to null or SANE_REALLOC_EMPTY.
amavect|11 months ago
I think my sane_realloc never freeing has much simpler behavior. As much as I hate the needless waste of 1 byte, if my code allocates thousands of 0-sized objects, I'd rather fix that before adding complexity to my sane_realloc.
With yours solving the 1 byte problem, it still interests me. We can simplify your code slightly.