views:

270

answers:

5

I've seen a lot of the following in older C code:

type_t *x = (type_t *) malloc(...);

What's the point of casting the pointer returned from malloc() since it's void *? Is it because older C compilers didn't support void pointers and malloc() used to return char * instead?

+1  A: 

It is the C-style way of writing type_t = new type_t.

jdv
+1  A: 

I'm not aware that malloc ever returned a char*.

But implicit casting from void* to type_t* (or any other type) hasn't always been allowed. Hence, the need to explicitly cast to the proper type.

abelenky
Prior to C89, malloc() returned `char *`. The `void *` type was introduced with C89 precisely because of the need for a "generic" pointer type that could be implicitly converted to any other pointer type. As of C89, there is no reason to explicitly cast the result of malloc().
John Bode
I stand corrected. I was never aware that malloc returned char* once upon a time. Good to know.
abelenky
A: 

What's the point of casting the pointer returned from malloc() since it's void *?

Quite the contrary. You need to cast a void pointer to an actual type before you can use it, because a void * signifies nothing about the data stored at that location.

casablanca
I am not attempting to dereference a void pointer without casting it. The point here is that the lvalue is a typed pointer and you still have to cast the rvalue before assignment.
Blagovest Buyukliev
A `void*` will be automatically converted to the corresponding `type_t*` on assignment
sth
Your argument only says why x (in the OP) must be type_t*, not why there must be a cast to assign the value there.
James Curran
-1 for incorrect usage of the word "cast", which refers to a `(type)` operator in C. You do need a conversion before the pointer can be used, but it will happen implicitly.
R..
+8  A: 

Your own explanation is the right one. Pre-ANSI C ('K&R' C) did not have a void * type with implicit conversion. char * doubled as a pseudo void * type, but you needed the explicit conversion of a type cast.

In modern C the casting is frowned upon because it can suppress compiler warnings for a missing prototype of malloc. In C++, the casting is needed (but there you should be using new instead of malloc most of the time).

Update

My comments below that try to explain why the cast is required were a bit unclear, I'll try to explain it better here. You might think that even when malloc returns char *, the cast is not needed because it is similar to:

int  *a;
char *b = a;

But in this example a cast is also needed. The second line is a constraint violation for the simple assignment operator (C99 6.5.1.6.1). Both pointer operands need to be of compatible type. When you change this to:

int  *a;
char *b = (char *) a;

the constraint violation disappears (both operands now have type char *) and the result is well-defined (for converting to a char pointer). In the 'reverse situation':

char *c;
int  *d = (int *) c;

the same argument hold for the cast, but when int * has stricter alignment requirements than char *, the result is implementation defined.

Conclusion: In the pre-ANSI days the type cast was necessary because malloc returned char * and not casting results is a constraint violation for the '=' operator.

schot
I also think this argument is the most plausible one. Yet even if malloc() returns char *, such a cast is technically not necessary because the type of the lvalue cannot be changed anyway.
Blagovest Buyukliev
schot
My remark tried to explain thatchar *c; int *x; x = c;is technically OK apart from the warning you would get from the compiler.
Blagovest Buyukliev
I think your wrong there, because of alignment issues: From C99 6.3.2.3 (7): "A pointer to an object or incomplete type may be converted to a pointer to a different object or incomplete type. If the resulting pointer is not correctly aligned for the pointed-to type, the behavior is undefined."
schot
Doesn't x = c; and x = (int *) c; produce absolutely the same machine code?
Blagovest Buyukliev
@Blagovest Buyukliev: `x = c` isn't required to compile at all - it violates a "shall" clause in the standard. It is legitimate for the compiler to reject it as an error rather than just issue a warning.
caf
@schot: Thank you for the insightful explanation. I now understand that this is a violation against the language specifications, but I couldn't get the stuff about alignment issues since we are not talking about dereferencing pointers. On the machine level, doesn't char *, int *, void *, or any other pointer look exactly the same and have the same alignment?
Blagovest Buyukliev
I think I actually understood it... You mean that by casting the pointer the actual address can be "rounded" to match the alignment of the target type?
Blagovest Buyukliev
+2  A: 

The problem here is not compatibility with any dialect of C. The problem is C++. In C++, a void pointer cannot be automatically converted to any other pointer type. So, without an explicit cast, this code would not compile with a C++ compiler.

slacker