Assigning pointers of different object types to each other is allowed as long as no alignment requirements are violated: The assignment will involve an (implicit) type conversion, so it is as (un)problematic as assigning a float
to an int
- it works in most cases but is allowed to blow up when a meaningful conversion is impossible.
char *
and void *
have compatible alignment requirements per spec, so assigning a char **
to a void **
variable (and vice versa) is never problematic. They even have compatible representation, which means in principle, accessing a char *
through an expression of type void *
- eg by dereferening a void **
which actually points to a char *
- will work as expected in most cases. Of course, the converse (accessing a void *
by dereferencing a char **
) holds true as well.
For example, the p
conversion specifier for printf()
expects a void *
and passing in an arbitrary pointer type is undefined behaviour. However, in case of char *
, it should work even on exotic architectures (eg with different pointer representations) as long as the implementation conforms to the C standard.
Where problems may arise is aliasing analysis: Due to the effective typing rules, a void **
and a char **
can't alias, and if the programmer breaks that promise, strange things may happen. One should realize that because of effective typing (aka strict aliasing), C is actually strongly typed - the type system is just very unsound (ie doesn't protect you from violating its invariants)...