tags:

views:

114

answers:

6

So, I have some function returning a pointer, or NULL on error. Now I'd like to add another possible value for a different error/condition. I heard this mentioned in some other answer before - using malloc() to create a unique pointer that will serve as a possible value for such functions to return (so now the can return a proper pointer, NULL or 0xWhatever and you can be sure 0xWhatever won't be used for anything else). So, naturally malloc(1) is probably a safe bet, but I was wondering if malloc(0) is also safe for this. Will a malloc(0) address possibly be used for something else? Can someone clarify on how this technique should work in general, and maybe what it is called?

+2  A: 

It is my understanding that in general, malloc(0) will "allocate" the memory which should still be freed later. It will give you a location in memory which you shouldn't write to.

You don't necessarily have to use malloc() to obtain a unique address, it could come from a static location for example. Then you could use this address as your other condition. Also leaves out the allocation as well. I don't recall the term for this use, something about a proxy.

#define ERRORPTR ((void *)&_unusedvar)
static char _unusedvar;

if ( /* failed */ )
    return ERRORPTR;
Jeff M
This is a nice expansion on @R..'s answer. +1.
Carl Smotricz
@Carl: more like he repeated mine. ;) But no matter, OP got the answer he's looking for.
Jeff M
+4  A: 

From the C99 standard:

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.

You're better off using malloc(1). That's guaranteed to return non-NULL if the memory is available.

paxdiablo
+1  A: 

Up to and I believe including C89, the meaning was unspecified. The standard simply had nothing to say about a non zero (or worse, negative) size. I'm reasonably sure it is now Implementation Defined. Use a non-zero size for portability.

You can evade the question by using the address of some global or static variable as a sentinel, perhaps with a suitable cast.

Another traditional approach (used in the earliest versions of signal(), IIRC) was to cast small integers other than 0 to the pointer type. This is actually relatively non portable, as the only integer that portably and safely casts to a pointer is 0, which is NULL.

Note that whether allocated or not, you would need to be careful never to attempt to actually free your sentinel pointer.

RBerteig
`malloc` takes an unsigned argument type (`size_t`) so there is no such thing as a negative size.
R..
RBerteig
+2  A: 

Somewhat tangential to the question, but having an "error condition pointer" (other than NULL) isn't really idiomatic C. If you want to write a function which allocates memory to a pointer and can return several distinct error conditions, there are two more usual ways to do it:

  1. Set errno to describe your specific error, and return NULL for all errors.
  2. Take a pointer-to-pointer as an argument, and return an integer error code

E.g.

sometype* my_function()
{
  sometype* p; 

  /* Do something */

  if (error_1_occurred) {
     errno = EAGAIN; /* Or whatever is appropriate */
     return NULL;
  } else if (error_2_occurred) {
     errno = EINVAL; /* Or whatever is appropriate */
     return NULL;
  } 

  p = malloc(/* whatever */);

  /* Do stuff */

  return p;
}

or

int my_function(sometype** pp) {

  if (!pp) return -99;

  /* Do something */

  if (error_1_occurred) {
     return -1;
  } else if (error_2_occurred) {
     return -2;
  } 

  *pp = malloc(/* whatever */);

  /* Do stuff */

  return 0;
}
Tyler McHenry
The second example is usually the most versatile. Take for instance asprintf(), which can return a variety of errors, or the number of bytes actually printed.
Tim Post
+3  A: 

Using malloc for this purpose is a very bad practice. Simply do:

static const char myerror;
return (void *)&myerror;

to get an "error value" pointer that will never compare equal to a pointer to any real object the rest of the program could obtain.

Edit: Originally I left out the &. Fixed.

R..
I like this approach! Assuming the original poster insists on ignoring all the considerations about "abusing" a return value for different types of information, this is a very viable way to implement a simple solution.
Carl Smotricz
+1  A: 

A NULL pointer is nothing but a pointer to the memory location whit address 0, since memory is usually paged in 4k chunks, you can use the numbers from 1 to 4095 to return other kind of errors in your function because that chunk of memory (0 - 4096) won't be paged for your application (unless you explicitly map it using mmap).

So it would be safe to do something like:

if(someError)

  return NULL;

else if(someOtherError)

  return (void *)1;

else
  /* Do something else */
SparkS
A *null pointer constant* is not necessarily represented by the value `0`.
Jens Gustedt