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

前端 未结 5 2066
迷失自我
迷失自我 2020-12-17 19:00

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 *         


        
5条回答
  •  [愿得一人]
    2020-12-17 19:30

    Types int** and void** are not compatible You are casting p, whose real type is int**, to void** and then dereferencing it here:

    *((void **) p) = pv;
    

    which will break aliasing rules.

    You can either pass a void pointer and then cast it correctly:

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

    or return a void pointer.

    int *pi = allocate_memory(sizeof *pi);
    


    There is an option to use a union:

    #include 
    #include 
    #include 
    
    union Pass
    {
        void** p ;
        int** pi ;
    } ;
    
    int allocate_memory(union Pass u , size_t s) {
        void *pv;
        if ( ( pv = malloc(s) ) == NULL ) {
            fprintf(stderr, "Error: malloc();");
            return -1;
        }
        printf("pv: %p;\n", pv);
        *(u.p) = pv;
    
        return 0;
    }
    
    int main() 
    {
        int* pi = NULL ;
        printf("%p\n" , pi ) ;
        allocate_memory( ( union Pass ){ .pi = &pi } , sizeof( *pi ) ) ;
        printf("%p\n" , pi ) ;
    
        return 0;
    }
    

    As far as I understand it, this example conforms to standard.

    Use static asserts to guarantee that the sizes and alignment are the same.

    _Static_assert( sizeof( int** ) == sizeof( void** ) , "warning" ) ;
    _Static_assert( _Alignof( int** ) == _Alignof( void** ) , "warning" ) ;
    

提交回复
热议问题