0

I read that void pointers can be casted to implicitly from any pointer, but it seems like they don't work with structs, I made an example:

typedef struct FOO{
    int *arr;
    size_t size;
} FOO;

int main()
{
    void * a;
    FOO * b = (FOO*)malloc(sizeof(FOO));

    a = b;

    b->arr;//works, accessed arr
    a->arr;//error: expression must have pointer-to-struct-or-union type
}

I can see that a and b have the same address but I can't use a as if it was of the same type as b, why is that?

Another related question is, can absolutely any pointer be implicitly casted to void *? Even FOO**** to void* for example?

shinzou
  • 5,850
  • 10
  • 60
  • 124
  • 1
    Standard Warning : Please [do not cast](http://stackoverflow.com/q/605845/2173917) the return value of `malloc()` and family in `C`. – Sourav Ghosh Apr 06 '15 at 14:32
  • @SouravGhosh uh I use VS so that's the standard I know... – shinzou Apr 06 '15 at 14:33
  • 1
    For your related question, any pointer at all, except for pointers to functions, there is no guarantee as to their size. – imreal Apr 06 '15 at 14:35
  • For the vocabulary, *casts* in C are those conversions were you write something like `(void*)` in front. These are *explicit* conversions and your code should usually not contain any of them. What you are doing in `a = b` is an implicit conversion from another pointer type *to* `void*`. – Jens Gustedt Apr 06 '15 at 16:01
  • Why the code shouldn't contain explicit casting? @JensGustedt – shinzou Apr 06 '15 at 16:37
  • @kuhaku, casting is always explicit. You mean explicit conversion? Because the compiler then supposes that you know what you are doing and all bets are off. C's type system is there to protect you: https://gustedt.wordpress.com/2014/04/02/dont-use-casts-i/ – Jens Gustedt Apr 06 '15 at 21:23

3 Answers3

1

a->arr; is equivalent to (*a).arr;. a is of void * type and it can't be dereferenced. You need to cast a to FOO * before dereferencing.

((FOO *)a)->arr;
haccks
  • 104,019
  • 25
  • 176
  • 264
1

You can assign any pointer type to void *, but you need to cast it back if you want to dereference it. Otherwise, the structure can't be known. A void has no structure/members and there is no mechanism to assume possible valid types for the memory pointed to by a void *.

shibley
  • 1,528
  • 1
  • 17
  • 23
1

That it would be more clear consider your example with minor changes

#include <stdlib.h>
#include <time.h>

typedef struct FOO1{
    int *arr;
    size_t size;
} FOO1;

typedef struct FOO2{
    int *arr;
    size_t size;
} FOO2;

int main()
{
    void * a;

    srand( ( unsigned int )time( NULL ) );

    int x = rand();

    if ( x % 2 == 0 )
    {  
        a = malloc( sizeof( FOO1 ) );
    }
    else
    {
        a = malloc( sizeof( FOO2 ) );
    }

    a->arr;
}

Can you say what object pointer a refers to?:)

Type void is incomplete type. You may note define objects of type void. But this expression

a->arr;

looks like "access data member arr of an object of type void".:)

So that the program above would compile you have to write something like

if ( x % 2 == 0 ) ( ( FOO1 * )a )->arr = NULL;
else ( ( FOO2 * )a )->arr = NULL;

That is you need to cast the pointer to the type of the object you are going to access.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335