What\'s the difference between const void *
and void *
? Under what circumstances can a void pointer be cast to a const void
pointer?
It's perfectly reasonable to cast a void *
to a const void *
and the compiler should do so implicitly behind the scenes without any thought on your part, but the other way around is dangerous and must be avoided.
Remember, if a function takes a const
pointer, then you're free to pass to it either a const
or a non-const
value. Saying you take a const
pointer is just you declaring that the memory won't be modified by your function.
An example: (note that the lines marked DANGER should throw a compiler error)
const void *p_const;
void *p_buffer;
// const pointers are allowed to hold static memory
p_const = "Foo"; // allowed
p_buffer = "Foo"; // DANGER!!!
// casting to const is implicit
p_const = malloc(LEN); // allowed - implicit cast
p_buffer = malloc(LEN); // allowed
// casting to const implicit again
write(STDOUT, p_const, LEN); // allowed
write(STDOUT, p_buffer, LEN); // also allowed - implicit cast
// const memory cannot be used where mutable memory is expected
read(0, p_buffer, LEN); // allowed
read(0, p_const, LEN); // DANGER!!
// To make the above more obivous, we'll skip the intermediate variable
// and place instead what it holds
read(0, malloc(LEN), LEN); // allowed - useless but at least no crashes
read(0, "foo", 4); // DANGER!!!
As a general rule, if a function you write takes in a pointer to a value that you're not going to modify, then the function signature should use a const
pointer. Using a pointer that isn't declared const
means that the memory you're pointing to is allowed to be modified.
Another example:
void do_something(const void* ptr, int length);
// Since the signature is a const pointer, I know I can call it like this:
do_something("foo",4);
Conversely, function calls for a non-constant pointer, then I have to allow for it:
void do_something(void* ptr, int length);
// This tells me that the function may overwrite my value.
// The safe solution therefore looks more like this:
char *myptr = char[4];
memcpy(myptr,"foo",4);
do_something(myptr,4);
Similarly, if you ever find yourself in a situation where you need to cast a const
pointer to a non-const
one, you should duplicate pointed-to value to a mutable part of memory, and pass your duplicate to the function rather than the original. If that sounds like a headache, that's because it is. If you find yourself in that situation, then you've probably done something wrong.
Conceptually, if the variable holds a "value", then it's likely a const
pointer. If, instead it holds a "buffer", then it's a non-const
pointer.
Pointers in you function signatures should always be declared const
unless you intend to write to that memory. Following that rule will help you avoid disastrous problems in your program's logic.
I didn't understand this simple rule until I had been programming for 6 years.