C
CBFalconer
Yevgen said:But p2 could also be changed. E.g. malloc and free could be
Please don't send email copies of usenet articles. It is just
further clutter and annoyance at this end.
Yevgen said:But p2 could also be changed. E.g. malloc and free could be
Richard said:It's stricter than that. It's not just implementation-dependent, but
implementation-defined. That means that the implementation's documentation
must tell you which choice it made.
For example, Microsoft's C compiler documentation says:
The calloc, malloc, and realloc functions accept zero as an argument. No
actual memory is allocated, but a valid pointer is returned and the memory
block can be modified later by realloc.
CBFalconer said:Not so. The standard requires malloced pointers to objects be
distinct. After the free(p) p is no longer a pointer to an object.
Er, I suspect this would break a lot of code...
...I believe you may have misspelled "No, I'm not" up above.
Would you mind clarifying your clarification?
CBFalconer said:Not so. The standard requires malloced pointers to objects be
distinct. After the free(p) p is no longer a pointer to an object.
jaysome said:On Mon, 18 Dec 2006 16:29:02 +0000, Richard Heathfield
The last sentence in the above quote is meant for your own good, and
has nothing to do with how the OS might misbehave (though it could).
All WIN32 platforms--95/98/ME/NT/2K/XP/2003/Vista/32/64--gracefully
handle null pointer dereferences.
2006-12-19 said:In the sense that it behaves that way. However you can't legally
dereference it, just as you can't alter an anonymous char string.
Random832 said:To what object does it point?
Harald said:It doesn't have a name, just as the result of malloc(sizeof(int))
doesn't have a name.
An object is defined as "region of data storage in the execution
environment, the contents of which can represent values". Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
Harald said:An object is defined as "region of data storage in the execution
environment, the contents of which can represent values". Since
malloc(0) must (if it doesn't return NULL) behave as if a positive
argument is passed, except for dereferencing, you still get a pointer
to a region. In particular, if you convert malloc's result to a
character pointer, it means you're allowed to increment it at least
once. The fact that you're not allowed to access the value is
irrelevant, since the definition doesn't state otherwise.
CBFalconer said:Since it points to zero storage bytes, it has already been
incremented to one past the storage area.
Simon Biber said:If you convert the pointer to char* and increment it, that
action is only valid if there is an object of at least one byte at the
address. So it could be argued that in effect you have used the
pointer to access an object.
Richard said:Chris Dollin said:If an implementation chose to return the same pointer P for each malloc(0)
then realloc would need to know that P was operationally equal
to null, and hence in your code above the realloc would just mallocate
100 bytes for your convenience.
Ok, now try this one:
char *p1, *p2;
p1=malloc(0); p2=malloc(0);
p1=realloc(p1, 200);
p2=realloc(p2, 100);
p1[123]='?';
If subsequent (non-free()d) calls to malloc(0) were allowed to deliver
identical pointers, that code would be allowed to make flying reindeer
come out of the North Pole.
But Santa is just a cheap copy of the real,
Dutch, Saint Nicholas, and that code (bad use of realloc() excepted)
does not have undefined behaviour. Therefore, all pointers returned from
malloc(0) must be either null or not equal to any other pointer,
including ones obtained from other calls to malloc(0).
Chris said:Since malloc() is a reserved function name, let me illustrate with
a different function-name. This also lets me use malloc() for the
"hard parts".
#include <stdlib.h>
static char magic;
void *nalloc(size_t size) {
if (size == 0)
return &magic; /* or: return NULL */
return malloc(size);
}
void nfree(void *p) {
if (p != &magic)
free(p);
}
void nrealloc(void *p, size_t size) {
if (p == &magic)
p = NULL;
if (size == 0) {
free(p);
return &magic; /* or: return NULL */
}
return realloc(p, size);
}
Given the obvious preconditions, the behavior of this code is
well-defined (which may suffice to label it "sensible"), but would
it suffice to replicate the Standard's requirements for malloc()?
I believe the answer is "no":
/* insert appropriate #include lines, etc., as needed */
#define Xalloc nalloc /* or malloc */
#define NAME "nalloc" /* or "malloc" */
#define Xfree nfree /* or free */
void check_it(void) {
void *p1 = Xalloc(0);
void *p2 = Xalloc(0);
if (p1 == NULL && p2 == NULL)
puts("OK: " NAME "(0) returned NULL each time");
else if (p1 == p2)
puts("FAIL: p1 == p2, but p1 and p2 are not NULL");
else {
puts("OK: alloc(0), called twice, returned two different")
puts("non-NULLs, or one non-NULL and one NULL");
}
Xfree(p1);
Xfree(p2);
}
>
If we use this check_it() routine on nalloc(), it will print the
"FAIL" line, because p1 and p2 are equal, yet at least one of the
two pointers is not NULL (in fact both point to the "magic" byte).
Keith Thompson said:In my opinion, the behavior defined by the standard for malloc(0) is
not particularly useful.
Random832 said:To what object does it point?
2006-12-19 said:Looks good, except that nrealloc should return void *.
Yes. Though if there weren't the explicit restriction in the standard:
"Each such allocation shall yield a pointer to an object disjoint
from any other object."
Keith said:*sniped* <
A quick test of a few systems I happen to have immediate access to
shows that all of them either return a null pointer, or return
distinct values on two successive calls to malloc(0).
As for why this is required, C99 7.20.3p1 says:
If the size of the space requested is zero, the behavior is
implementation-defined: either a null pointer is returned, or the
behavior is as if the size were some nonzero value, except that
the returned pointer shall not be used to access an object.
One aspect of the behavior of malloc() with a non-zero size is that
successive calls return unique values. My interpretation is that this
same behavior is required for non-null results of malloc(0).
The simplest way to implement this is to quietly translate "malloc(0)"
to "malloc(1)".
WaterWalk said:Does this imply that if an implementation makes malloc(0) return
a non-null pointer, this pointer shall be free()d?
Stephen Sprunk said:To the zero-byte object that malloc() allocated
Of course, asking for details about a zero-byte object is pointless,
since an object of zero bytes has no properties other than an
address. It's like asking about properties of a object of type void
(and I don't mean void*).
Harald's comment about being able to increment a pointer to a
zero-byte object is interesting, though. Should that be legal? IMHO,
the pointer already points to the byte after the end of the object
when you get it, and it'd be UB to try to increment it -- or decrement
it.
Want to reply to this thread or ask your own question?
You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.