Is it good practice to access a pointer variable by dereferencing a pointer to a pointer, which points to a different type or void
? Could this break strict aliasing rules? C and C++ have some differences in aliasing rules. In this question we focus on C. The other question considering C++ can be found here. In the following example a double*
is accessed as a void*
.
int create_buffer(void** ptr, ...)
{
*ptr = malloc(...);
...
}
int main(void)
{
double* buffer;
// The problematic code is here, double**
// is coerced to void**, which is later
// dereferenced by the function
create_buffer((void**)&buffer, ...);
...
}
Is the following any better:
// keeping void** just as an indicator in the interface
// that the pointer is pointing to a pointer to any type
// it could be replaced by just void*
int create_buffer(void** ptr, ...)
{
void* result = malloc(...);
memcpy((void*)ptr, &result, sizeof result);
}
Not answering your question, but you could manoeuvrer around the uncertainties you mention by just doing well defined stuff like:
int main(void)
{
double* buffer;
{
void * pv;
create_buffer(&pv, ...);
buffer = pv; /* C does not need any cast here. */
}
...
I would rather write it like this, assuming you use the "int" to return some useful information to the caller that it can't do without:
void *create_buffer(size_t n, int *otherInfo) {
void *ptr = malloc(n);
*otherInfo = 0;
if (ptr) {
// Do whatever other initialization is expected
// memset(ptr, 0, n);
} else {
*otherInfo = -1;
}
return ptr;
}
int main(void)
{
double* buffer;
int code;
/* cast is not required by language or compiler,
but I still find it useful when reading */
buffer = (double *)create_buffer(SIZE_REQUIRED, &code);
/* equality testing can be done either way. This way here,
if you ever forget a =, will never compile anywhere. Nowadays
many compilers are smart enough to catch it on their own anyway */
if (NULL == buffer) {
// Handle out of memory error or other problem
switch(code) {
case -1:
fprintf(stderr, "Out of memory\n");
...
default:
fprintf(stderr, "Unexpected error %d\n", code);
break;
}
}
}