Peter Nilsson said:
In which Bjarne Stroustrup writes:
| Dennis Ritchie and Brian Kernighan are among the most thoughtful of
| people. They did have a choice at the time. If they had thought it
| important/best to leave malloc calls uncast they could have (1) used
| the ANSI C compiler or (2) edited the casts out in the final draft
| (after the final check with the ANSI C compiler) or (3) politely asked
| me for a compatibility feature in Cfront (we talked almost every day).
|
| I think it is safest to assume that when Dennis Ritchie and Brian
| Kernighan did something, it was because they wanted to do that and not
| the opposite.
But the errata list for K&R2 acknowledges that casting the result of
malloc isn't such a good idea after all.
<
http://netlib.bell-labs.com/cm/cs/cbook/2ediffs.html>:
142 (section 6.5, toward the end): The remark about casting the
return value of malloc ("the proper method is to declare ... then
explicitly coerce") needs to be rewritten. The example is correct
and works, but the advice is debatable in the context of the
1988-1989 ANSI/ISO standards. It's not necessary (given that
coercion of void * to ALMOSTANYTYPE * is automatic), and possibly
harmful if malloc, or a proxy for it, fails to be declared as
returning void *. The explicit cast can cover up an unintended
error. On the other hand, pre-ANSI, the cast was necessary, and it
is in C++ also.
In which P.J. Plauger, replying to Richard Heathfield, writes:
| I thought I had given more than one reason, en passant, but here's a
| quick review. Indeed the first motivation we had for adding casts to
| malloc calls was to satisfy a market need to have all our Standard C
| library compile either as C or C++. The C++ Standard (thanks to me)
| deliberately permits the C library to have either extern "C" or
| extern "C++" linkage -- and we have serious customers for both
| flavors. Having done so, we then found reasons to make *all* of our
| C source code compilable as C++.
|
| Generally I avoid casts for the reason so often given -- they're so
| strong that they often hide problems. We add them where required for
| correctness, for portability, for C++ compatibility, and to quiet
| silly warnings. Our experience over the years is that the last
| category of casts do indeed raise the cost of maintenance -- we fix
| something here and the forgotten consequences there are masked by
| the cast, until we discover the bug by a painful runtime trace.
|
| But allocator casts often *help* us find bugs that arise during
| maintenance. The classic pattern is a structure declared here,
| containing a pointer to another structure declared somewhere else,
| for which storage is allocated there, and freed some other
| there. That's why we allocate N times the size of the thing we
| really want, cast the resultant pointer to a pointer to that type,
| and store it in what should be a compatible type of pointer. We've
| had the compiler inform us of bugs in both size and pointer types as
| the code changes under maintenance and enhancement.
|
| In our environment, bugs like failing to include stdlib.h get found
| and fixed in the first pass or two of code writing. We generally
| perform *many* passes over our code during development, and develop
| a companion set of tests. So the kind of bugs masked by casts on
| malloc are cheap to fix, while the kind exposed by such casts are
| much more expensive.
But I believe the bugs exposed by casting the result of malloc can be
avoided by using the clc-recommended idiom:
ptr = malloc(COUNT * sizeof *ptr);
even if "ptr" is some more complex expression.