Question:
In some code snippets, I observe the conversion of malloc()
to (char *)
, (int *)
, etc. Why is this done?
For instance:
char *p;
p = (char *) malloc(100 * sizeof(char));
Answer:
In the days of the dinosaurs, there was no void *
type in the C language. The idea of a generic void *
pointer came to C much later (and not from anywhere, but from C ++). Until that time, it was char *
that was used as a "universal" pointer type. The malloc
function returned the result exactly of the char *
type. It was at that time that there was a need to perform an implicit casting of the result of malloc
from char *
to a specific type of a receiver pointer. In code examples written in pre-standard C, including early versions of K&R, this cast is everywhere for this very reason.
With the appearance in the language of the void *
type, which is implicitly cast to any pointer type, and with the subsequent transition from malloc
to void *
, the need for an explicit cast has disappeared. However, you can still see it in a lot of old code. This reduction also migrated to the second edition of K&R C, which was written before the first C standard appeared. Despite the fact that the second edition was retroactively brought into compliance with the C89 / 90 standard, no one corrected the code examples in it. As a result, students using the K&R book for teaching "pick up" this strange habit from there, blindly following it as a "cargo cult".
In modern C code, it makes sense to perform such a cast only in cross-compiled C-C ++ code, since C ++ does not void *
pointer to other types by itself. In particular, for example, when implementing cross-compiled macros and inline functions in header files.
(A legacy from the days when char *
used as a generic pointer in C in the modern language specification is to ensure that the object representation and alignment requirements of void *
and char *
must match.)
For the sake of fairness, it should be noted that one argument of modern fans to explicitly malloc
result in C code (not intended for cross-compilation) still contains a certain rational grain. In code like
T* p;
...
p = (T *) malloc(N * sizeof(T));
if someone changes the type of the pointer in the p
declaration from T *
to U *
, but at the same time forgets to correct the memory allocation through malloc
, then in the call to malloc
compiler will generate a diagnostic message about the inconsistency of pointer types. Yes this is true.
However, a more intelligent way of protecting against such problems would be to use the idiom with "type-independent" memory allocation
p = malloc(N * sizeof *p);
which itself "automatically" adjusts to the above type change.