Search code examples
cpointersstrict-aliasing

How to cast the address of a pointer generically while conforming to the C standard


It is common to assign pointers with allocations using an implicit function-return void * conversion, just like malloc()'s:

void *malloc(size_t size);
int *pi = malloc(sizeof *pi);

I would like to perform the same assignment while passing the address of the target pointer, and without explicitly casting its type from within the function (not within its body, nor arguments).

The following code seems to achieve just that.

  1. I would like to know whether the code fully conforms with (any of) the C standards.
  2. If it doesn't conform, I would like to know if it's possible to achieve my requirement while conforming to (any of) the C standards.

.

#include <stdio.h>
#include <stdlib.h>

int allocate_memory(void *p, size_t s) {
    void *pv;
    if ( ( pv = malloc(s) ) == NULL ) {
        fprintf(stderr, "Error: malloc();");
        return -1;
    }
    printf("pv: %p;\n", pv);
    *((void **) p) = pv;
    return 0;
}

int main(void) {
    int *pi = NULL;
    allocate_memory(&pi, sizeof *pi);
    printf("pi: %p;\n", (void *) pi);
    return 0;
}

Result:

pv: 0x800103a8;
pi: 0x800103a8;

Solution

  • No, this is not compliant. You're passing an int** as void* (ok), but then you cast the void* to a void** which is not guaranteed to have the same size and layout. You can only dereference a void* (except one gotten from malloc/calloc) after you cast it back to the pointer type that it originally was, and this rule does not apply recursively (so a void** does not convert automatically, like a void*).

    I also don't see a way to meet all your requirements. If you must pass a pointer by pointer, then you need to actually pass the address of a void* and do all the necessary casting in the caller, in this case main. That would be

    int *pi;
    void *pv;
    allocate_memory(&pv, sizeof(int));
    pi = pv;
    

    ... defeating your scheme.