why is casting malloc a bad thing?

M

Mark McIntyre

I've now accumulated enough evidence that you're incapable of
reading accurately what others write, particularly when you don't
agree with them.

The only way you can have achieved that accumulation is by failing to
read properly what I've written myself. So I propose to stop being
interested in your postings, to avoid further unpleasantness.
And you haven't even noticed that I'm *not* advocating this
position to C programmers in general.

Then your powers of explaination are much less good than you think.
 
M

Mark McIntyre

Now you're simply being a jerk.

And you, sir, have absolutely no sense of humour whatsoever. Come on,
you dolt, I'm not being nasty to you, you have one blind spot, I
forgive you, now grow up.
From your earlier posting:

(snip completely irrelevant requote)
 
S

Sidney Cadot

As I see it, as a member of the 'anti-cast' crowd, the problem is
with the very notion of a 'pro-cast' position (a la Tisdale). We
see no possible rationale for this in terms of the C programming
language.

And that's ok for me. Limiting oneself to the context of the C
programming language (thus waiving the C++ compatibility argument for a
moment), I can see only one defense for malloc casting, which I
personally think is an important one: rigorous type discipline. if I
look at the free-standing expression "malloc(50*sizeof(double))" it is
clear that this should by intent be of type double*, but it is in fact
of type void*. I correct the compilers' misconception about this type by
a cast.

I know that in most contexts this isn't necessary because it will be
assigned to a typed pointer immediately after, but still it brings the
expression under the compiler's type checking regime a little bit
earlier, preventing such silliness as:

int *x = malloc(50*sizeof(double));

since

int *x = (double *)malloc(50*sizeof(double));

is an error.

Now I've seen all the counter-arguments to this by now, but in the end I
simply feel that malloc(50*sizeof(double)) is incorrectly typed as
void*, and that's all there is to it as far as I am concerned. Most here
disagree, their argumentation is clear and not without merit. I do feel
however that my stand on this is quite defensible, and will keep saying
so until either I or the whole lot of you changes sides ;-)
On the other hand, P.J. Plauger's basic position seems perfectly
reasonable, namely that there are some special contexts where a
body of code has to be compiled indifferently as C or as C++, and
in those special contexts casting the return from malloc is
required (and does no harm if we can assume that the coder is
astute enough to ensure that <stdlib.h> is always #included).

This, it seems to me, is not a 'pro-cast' position: it's just
saying that real-world considerations other than "good C
programming" sometimes dictate a cast. Fair enough.

Yes. Above, I try to put up a defense for the more extreme 'pro-cast'
position that doesn't invoke the C++ scenario. Feel free to dismiss it.

Best regards,

Sidney
 
A

Allin Cottrell

Sidney said:
Limiting oneself to the context of the C
programming language (thus waiving the C++ compatibility argument for a
moment), I can see only one defense for malloc casting, which I
personally think is an important one: rigorous type discipline. if I
look at the free-standing expression "malloc(50*sizeof(double))" it is
clear that this should by intent be of type double*, but it is in fact
of type void*. I correct the compilers' misconception about this type by
a cast.

I know that in most contexts this isn't necessary because it will be
assigned to a typed pointer immediately after, but still it brings the
expression under the compiler's type checking regime a little bit
earlier, preventing such silliness as:

int *x = malloc(50*sizeof(double));

Of course, that sort of silliness is taken care of (even if many lines
separate the

int *x;

from the malloc() call), by the clc recommended practice of

int *x = malloc(50 * sizeof *x);
 
D

Dan Pop

In said:
I know that in most contexts this isn't necessary because it will be
assigned to a typed pointer immediately after, but still it brings the
expression under the compiler's type checking regime a little bit
earlier, preventing such silliness as:

int *x = malloc(50*sizeof(double));

since

int *x = (double *)malloc(50*sizeof(double));

is an error.

Now I've seen all the counter-arguments to this by now, but in the end I
simply feel that malloc(50*sizeof(double)) is incorrectly typed as
void*, and that's all there is to it as far as I am concerned.

In most cases, malloc(50*sizeof(double)) is considered bad style.
Consider the alternative:

double *x = malloc(50 * sizeof *x);

Casting to double * not only doesn't add anything, because there is no
place left for the error you're talking about, but it is a maintenance
headache if the type of x ever needs to be changed, say to pointer
to long double: instead of making one change, you have to make two,
for no redeeming advantage.

Dan
 
B

Bjarne Stroustrup

IIRC, the pre-ANSI C mallloc returned char *. That required an
explicit cast any time its return value was not assigned to a char *.
So, it is very likely that Kernighan was doing it out of habit.

But there is another reason, mentioned in the preface:

We used Bjarne Stroustrup's C++ translator extensively for local
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
testing of our programs, and Dave Kristol provided us with an ANSI
^^^^^^^^^^^^^^^^^^^^^^^
C compiler for final testing.

Since C++ requires the cast, the authors had no chance but to use it.

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.

-- Bjarne Stroustrup; http://www.research.att.com/~bs
 
D

Dan Pop

In said:
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.

They officially "repented" for doing it. See the K&R2 errata at
http://cm.bell-labs.com/cm/cs/cbook/2ediffs.html

142(§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.

Dan
 
J

Joona I Palaste

Bjarne Stroustrup said:
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.

At the risk of sounding like an idiot, I have to ask you what you mean
by "the opposite". Do you mean that Ritchie and Kernighan did <X>
because they wanted to do <X> instead of the opposite of <X>? Or do
you mean that they did something because they wanted to do it, not
because they didn't want to do it?
 
R

Richard Bos

P.J. Plauger said:
Sorry, I was being cute at the cost of some precision. And I certainly
didn't intend to be insulting with that statement

I know you didn't. That's one reason why, it coming from you, I wasn't
insulted.
My point was that you *can* write malloc calls
without casts only because the C committee gave them special
dispensation.

But this isn't true! You can write malloc() calls without casts because
malloc() returns void *. Now, void pointers have special dispensation
from needing casts; but this has nothing specifically to do with
malloc(). It's a general property of void *s, also often used in qsort()
callback functions, for example.
I have trouble feeling wrong when I'm trying to state a more
ecumenical position than damn near anybody else in this thread.

Your ecumenicality on casts has nothing to do with the above sentence;
you are simply provably wrong on _my_ position on casts, which is a
level of opinionatedness extra :).
IOW, regardless of which of us is right about casts, you're wrong about
_me_.
It's fine with me if you adopt this style, particularly having thought
it through. It's less fine that you and others absolutely refuse to
let in the possibility that well meaning people might arrive at a
different conclusion on such a delicate matter of style.

Ah, well, you see, that's because I've ever only heard of three
arguments for the cast, and several against; and those against are of
higher quality than those for.

For the casts, we have "I have customers who need to compile this on all
kinds of compilers, and I cannot hand-gear my code for every single
situation" (you, and AFAICT, nobody else); "But it breaks when I compile
my C code on my C++ compiler!!!" (all newbies in the world, seemingly,
and Tisdale); and "The code with the cast is more solid and type-safe"
(several kinds of trolls and confused newbies).
The first argument, yours, holds some water, but only in exceptional
circumstances. Now, _you_, in fact, are in exceptional circumstances,
being an implementation writer and creator of code for others, so this
argument holds water for you. I don't think I've ever seen anyone else
in c.l.c to whom it applies, though.
To the second argument, one need only say "Well, don't do that, then",
just as to people who complain that their C code won't compile as Java.
As for the third argument, it is demonstrably false; and has been shown
to be false repeatedly in this newsgroup.
If you know of any other argument _for_ the casts, one which applies to
your average programmer and not just to someone who, like you, has
special requirements, and one which actually stands the test of c.l.c,
I'd love to hear it.

Against casting malloc(), we have several arguments, ranging from
shorter typing and less cluttered code, through the demonstration that
code without the cast, written properly, is actually _more_ solid than
code with it, to my own more philosophical argument that _any_ warning
sign is bad when over-used, because it devaluates the warning where it
is necessary; the "cry wolf" argument. All of those have been argued
more than once (or twice, or a thousand times) here; I have never seen
any of them properly refuted.

In the end, then, we may come across as somewhat curt, sometimes; but
that is because all these arguments have already been brought forward,
they're now just being re-hashed over and over again, and we've all
already made up our minds, in a perfectly rational way, a long time ago.
And each time Mr. Tisdale, or someone else, pulls out yet another
re-statement of the same tired old "but C is just C++ stripped down, and
I want to compile C as C++", we, at least I, do get just a little weary.
But that doesn't mean we haven't thought about it. We _have_, over and
over again; that's the reason.

Richard
 
T

Tak-Shing Chan

As for the third argument, it is demonstrably false; and has been shown
to be false repeatedly in this newsgroup.

AFAICT it has /not/ been shown false. The lack of malloc
casts could actually hide undefined behaviors:

#include <stdio.h>
#include <stdlib.h>

double *x; /* Wrong declaration */

int
main(void)
{
x = (int *) malloc(sizeof *x);
if (x) {
*x = 4;
printf("%d\n", *x); /* Undefined behavior */
free(x);
}
return 0;
}

With the malloc cast, you are guaranteed a diagnostic.
Without the cast, the diagnostic is not required. Bad style
perhaps, but this possibility should not be dismissed.

Tak-Shing
 
S

Sidney Cadot

Dan said:
In most cases, malloc(50*sizeof(double)) is considered bad style.
Consider the alternative:

double *x = malloc(50 * sizeof *x);

That's funny, my lone expression seems to have turned into a full-blown
declarator/initializer as if by magic.

My point, as you know by now but choose to ignore, is that the malloc
expression itself should be properly typed as a double*.
Casting to double * not only doesn't add anything, because there is no
place left for the error you're talking about, but it is a maintenance
headache if the type of x ever needs to be changed, say to pointer
to long double: instead of making one change, you have to make two,

That's true. In fact, it's more of a "maintenance headache" than what
your preferred notation introduces when changing the identifier name
(but only slightly).
for no redeeming advantage.

The redeeming advantage, to me, is the knowledge that I have corrected
the misconception of the compiler about the type of an object at the
earliest possible opportunity.

That way, I don't have to rely on the semantics of C with regard to
allowing void*-to-any* assignments, which I think are an ugly wart on
C's type safety system.

An analogy may help. Here in Holland, it aggrieves me to say, we have no
law forbidding the wearing of white socks under a suit. But that doesn't
mean I don't make an effort to avoid being dressed like that.

Best regards,

Sidney
 
D

Dik T. Winter

I have not seen the base article, hence my response to this:

It did indeed return a char *. And no, it did not require an explicit
cast any time its return value was not assigned to a char *. Pre-ANSI
C did not require casts on pointer assignments, the requirement came
with ANSI C.
 
D

Dan Pop

In said:
That's funny, my lone expression seems to have turned into a full-blown
declarator/initializer as if by magic.

No magic at all: you have used it as such, in your own examples. Hence
my counterexample.
My point, as you know by now but choose to ignore, is that the malloc
expression itself should be properly typed as a double*.

Nope, because it never used as an expression by itself: it's always used
either as an initialiser or as a subexpression of a wider expression
which establishes its intended type.
That's true. In fact, it's more of a "maintenance headache" than what
your preferred notation introduces when changing the identifier name
(but only slightly).

If you ever have to change identifier names in your code, there is
something very wrong with your coding methodology.
The redeeming advantage, to me, is the knowledge that I have corrected
the misconception of the compiler about the type of an object at the
earliest possible opportunity.

The compiler has no misconceptions about anything.
That way, I don't have to rely on the semantics of C with regard to
allowing void*-to-any* assignments, which I think are an ugly wart on
C's type safety system.

I'm afraid that few C programmers share your views.
An analogy may help. Here in Holland, it aggrieves me to say, we have no
law forbidding the wearing of white socks under a suit. But that doesn't
mean I don't make an effort to avoid being dressed like that.

So, what kind of socks are you wearing under a white suit?

Dan
 
D

Dan Pop

In said:
I have not seen the base article, hence my response to this:


It did indeed return a char *. And no, it did not require an explicit
cast any time its return value was not assigned to a char *. Pre-ANSI
C did not require casts on pointer assignments, the requirement came
with ANSI C.

A certain Dennis M. Ritchie seems to be thinking otherwise. From the
K&R2 errata (I've already posted the full quote):

On the other hand, pre-ANSI, the cast was necessary, and it is in
C++ also.

K&R1 explains the dangers of omitting the cast, at page 192.

Dan
 
I

I.M.A Troll

Richard said:
when both sides are using
words like "idiot" and "nonsense". I dread to think what must be going
through the newbies' heads as they read your exchange with Mr Plauger.
We're loving it! Don't stop.
 
S

Sidney Cadot

Dan said:
No magic at all: you have used it as such, in your own examples. Hence
my counterexample.

Ah, yes. I was trying to make a point about the expression
'malloc(50*sizeof(double))', but I can see where the confusion comes from.
Nope, because it never used as an expression by itself: it's always used
either as an initialiser or as a subexpression of a wider expression
which establishes its intended type.


Unfortunately, all examples where the result of malloc() is not
immediately assigned (or something similar) look contrived, yes. That
doesn't invalidate the point. This fact-of-life is incidental, not
essential, for the purpose of this discussion.
If you ever have to change identifier names in your code, there is
something very wrong with your coding methodology.

To me, that sounds like a bizarre statement. Please elaborate.
The compiler has no misconceptions about anything.

I disagree. Provided the malloc has succeeded, there is a bunch of
consecutive bytes floating around, intended to be used as a double
array. Such a bunch of bytes should properly be typed double *.

Unfortunately, the C language lacks a new operator that yields a
properly typed result. We have to make do with malloc, which has little
choice other than to return a void *. This constraint of the language
leads to the weird situation that a pointer to memory area that should
be properlt typed is not (yet) properly typed. I think it's right to
call this a misconception on the side of the compiler, and I think it's
right to correct this.
I'm afraid that few C programmers share your views.

I'm afraid you're right.
So, what kind of socks are you wearing under a white suit?

I have no idea. My analogy invertor comes up empty.

Best regards,

Sidney
 
H

Holger Hasselbach

Sidney said:
[...]
My point, as you know by now but choose to ignore, is that the malloc
expression itself should be properly typed as a double*.
[...]
The redeeming advantage, to me, is the knowledge that I have corrected
the misconception of the compiler about the type of an object at the
earliest possible opportunity.

That way, I don't have to rely on the semantics of C with regard to
allowing void*-to-any* assignments, which I think are an ugly wart on
C's type safety system.

Do you rely on the promotion rules? Do you think that the rules with
all the implicit conversions between signed/unsigned int types, float,
double, etc. for numbers provide more type safety than the void* to
any* conversions for pointers? Or do you always write something like
this:

char c = (char)((int)'0' + (int)9);

As I previously wrote far below in the thread, there are three
situations where, for a pointer d, the types of d and *d are relevant:

Assignment: d[10] = 5.3;
Read + arithmetics: a[5] = d[10] * 1.7;

Low level memory management including pointer arithmetic:
d = malloc(50 * sizeof(*d));
memcpy(&d[10], &a[5], 5 * sizeof(*d));
a = d + 10;

What happens when the types of d and a are changed to int*? The memory
functions will work perfectly without change, in fact the type does
not matter at all. For the above assignment and read, you will get an
unexpected result for a[5]. Do you care for it with casts? Caring for
the type where the language provides anything to completely abstract
it away, and not caring for it where it really matters is at least a
bit inconsequent, IMHO.


Holger
 
S

Sidney Cadot

Holger said:
Sidney said:
[...]
My point, as you know by now but choose to ignore, is that the malloc
expression itself should be properly typed as a double*.
[...]
The redeeming advantage, to me, is the knowledge that I have corrected
the misconception of the compiler about the type of an object at the
earliest possible opportunity.

That way, I don't have to rely on the semantics of C with regard to
allowing void*-to-any* assignments, which I think are an ugly wart on
C's type safety system.


Do you rely on the promotion rules? Do you think that the rules with
all the implicit conversions between signed/unsigned int types, float,
double, etc. for numbers provide more type safety than the void* to
any* conversions for pointers? Or do you always write something like
this:

char c = (char)((int)'0' + (int)9);

I rely on the rules that I think are reasonable. This includes your
sample case (so I don't use casts there), and things like implicit
int-to-float conversion.

I do not rely on the rules that I think are unreasonable. This includes
implicit void*-to-any* conversions, but also implicit float-to-int
conversions.

So I would never write:

intVar = floatVar;

But I would always use an explicit cast (and only in cases where I do
not care too much about rounding).
As I previously wrote far below in the thread, there are three
situations where, for a pointer d, the types of d and *d are relevant:

Only three?
Assignment: d[10] = 5.3;
Read + arithmetics: a[5] = d[10] * 1.7;

Low level memory management including pointer arithmetic:
d = malloc(50 * sizeof(*d));
memcpy(&d[10], &a[5], 5 * sizeof(*d));
a = d + 10;

What happens when the types of d and a are changed to int*? The memory
functions will work perfectly without change, in fact the type does
not matter at all. For the above assignment and read, you will get an
unexpected result for a[5].

I think "unexpected" is a very subjective term... I do not think
anything would happen that I did not expect.
Do you care for it with casts?

As stated above, I make an effort to avoid implicit float-to-int
conversions.
Caring for
the type where the language provides anything to completely abstract
it away, and not caring for it where it really matters is at least a
bit inconsequent, IMHO.

Mastery of any subject is not about knowing the rules, but perhaps more
about good judgement about when to break them.

(Not that it applies of course, but it sounds quite profound)

Best regards,

Sidney
 
Z

Zoran Cutura

Dan Pop said:
If you ever have to change identifier names in your code, there is
something very wrong with your coding methodology.

I admit that from time to time it becomes necessary to change an
identifiers name. That would IMHO be probably only be necessary with
file scope identifiers, as the usage of local identifiers is probably so
clear when you first type its name that it happens rather seldom to me
that I have to change its name. Sometimes when a file scope identifier
is not named carefully, it may become necessary to change its name, but
than there are tools to change one string into another, most editors can
do this within one step and if the usage is split over more files
"sed"-like tools are your friend.

IMHO it is very much easier to change an idenitifier everywhere it is
used, than searching all the code for "assumptions" about the type of an
identifier.
 
D

Daniel Haude

On Mon, 26 Jan 2004 22:54:26 GMT,
in Msg. said:
1) Style rules should be developed by considering all applicable
principles and weighing their various importance *for that particular
rule*.

So if you write a function that expects a void pointer but uses another
type internally (like the compare function for qsort), would you do it
like this?

int foo(void *a)
{
struct whatever_struct *s = (struct whatever_struct *) a;
/* ... */
}

--Daniel
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,777
Messages
2,569,604
Members
45,218
Latest member
JolieDenha

Latest Threads

Top