why is casting malloc a bad thing?

D

Daniel Haude

On Wed, 28 Jan 2004 18:49:52 +0000,
Tak-Shing Chan said:
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);

When you start casting x here, why not cast it everywhere you use it? This
doesn't have to do with malloc().

--Daniel
 
D

Daniel Haude

On 26 Jan 2004 13:42:11 GMT,
in Msg. said:
Why would a C++ compiler need to worry about malloc()'ing code? They have
memory allocation schemes of their own in C++.

....and indeed, IIRC, you're recommended to only use new to allocate memory
in C++ anyway; malloc() is considered bad style. Which gives us yet
another reason against the cast: When C++ balks about an uncast malloc()
it's time to change it to "new" instead (and to get rid of the
corresponding free() as well). But this is OT on clc.

--Daniel
 
D

Daniel Haude

On Thu, 29 Jan 2004 01:08:46 +0100,
in Msg. said:
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).

Changing an (presumably unique) identifier name is a piece of cake unless
you use a mechanical typewriter for writing source code. But automatically
changing the multiply-used type of an object with a text editor is a bit
more difficult.

--Daniel
 
D

Daniel Haude

On Thu, 29 Jan 2004 01:08:46 +0100,
in Msg. said:
That way, I don't have to rely on the semantics of C with regard to
allowing void*-to-any* assignments,

When programming in C you have to rely on the semantics of C with regard
to pretty much anything.

--Daniel
 
R

Richard Bos

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

Not unless there is more wrong.
#include <stdio.h>
#include <stdlib.h>

double *x; /* Wrong declaration */

Very unusual. Generally one knows what kind of data one wants when one
declares it; only while using them do you sometimes get confused.
int
main(void)
{
x = (int *) malloc(sizeof *x);
if (x) {
*x = 4;
printf("%d\n", *x); /* Undefined behavior */

You know, I'd expect to get a warning; and I'd expect malloc()-casters
to cast away that warning by writing

printf("%d\n", (int)*x);

or even

printf("%d\n", *(int *)x);
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.

Actually, I do dismiss this possibility, because I don't believe it
happens that way.

Moreover, it is not a reason to cast malloc() in particular. Would you
also expect to see the cast on

int *y;

y = (int *)x;

If not, why make an exception for malloc()?

Richard
 
P

pete

Daniel said:
On Mon, 26 Jan 2004 22:54:26 GMT,


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;
/* ... */
}

No.

struct whatever_struct *s = a;

a needs to be holding a valid (struct whatever_struct *) type
value to begin with, or your code's no good.

void qsort(void *base, size_t nmemb, size_t size,
int (*compar)(const void *, const void *))
{
unsigned char swap, *p1, *p2, *end, *array, *i, *j, *k, *after;
size_t bytes;

array = base;
after = nmemb * size + array;
if (nmemb > (size_t)-1 / 3) {
nmemb = (size_t)-1 / 3;
}
do {
bytes = nmemb * size;
for (i = bytes + array; i != after; i += size) {
j = i - bytes;
if (compar(j, i) > 0) {
k = i;
do {
p1 = j;
p2 = k;
end = p2 + size;
do {
swap = *p1;
*p1++ = *p2;
*p2++ = swap;
} while (p2 != end);
if (bytes + array > j) {
break;
}
k = j;
j -= bytes;
} while (compar(j, k) > 0);
}
}
nmemb = nmemb != 2 ? 3 * nmemb / 8 : 1;
} while (nmemb);
}
 
M

magesh

Well I am not sure to measure upto u guys, my question may be redundnant.
My question is this, if people pretend with their own arguments
that casting malloc return may cause undefined behaviour, I would like
to know

double* p = malloc(8*sizeof(double));==>OK for some here because
implicit coversion is well enough
but why
double* p = (double*) malloc(8*sizeof(double));==>NOK for some.

I assume that casting the malloc's return is just an indication for my
codevelopers who may see an assignement of p from a malloc a 500 or more
lines after my pointer declaration p.

If we prentend that implicit conversion is safe and the fact of casting
may cause UB due to probable alignement problems, its a bit difficult to
understant why implicit conversion may be safer than an explicit more
than a matter of style.
Does compilers treat them differently?
 
H

Holger Hasselbach

Sidney said:
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).

Occasionally I use explicit casts in that case, too, to silence
over-paranoid compilers ("It's my intention to be unprecise, so shut
up!"). In full awareness that it could introduce serious unwarned bugs
when the intVar is later changed to a longVar without modifying the
cast, when the type is not abstracted by a typedef. But that's another
thing than to not rely on it. To not rely on it has something of to
not trust its correctness of implementation or the correctness of the
rules themself.

Why exactly do you think that the float-to-int conversion is
unreasonable?

Do you think that an explicit conversion is "more correct" than an
implicit one? I'm quite sure that any existing conforming compiler
will produce exactly the same result in intVar for both cases.

Why exactly do you think that the void*-to-any* conversion is
unreasonable? What exactly could go wrong in the implicit semantics?

Did you have any situations where you experienced the failure of the
implicit conversions (in both int and void), which you successfully
cured with an explicit cast? And that you could blame on the
semantics, not on a broken non-conforming compiler?
Only three?

Can you give another one that does not fit into one of these three?

[...]


Holger
 
R

Richard Bos

magesh said:
Well I am not sure to measure upto u guys, my question may be redundnant.
My question is this, if people pretend with their own arguments
that casting malloc return may cause undefined behaviour,

Nonsense - nobody has "pretended" that. Casting malloc() may _hide_
undefined behaviour which is present in the code whether there is a cast
or not. If you call malloc() without a declaration in scope for it, you
always invoke undefined behaviour. The cast doesn't change that fact.
What it does do is stop the compiler from telling you about it.

Richard
 
S

Sidney Cadot

Richard said:
Nonsense - nobody has "pretended" that. Casting malloc() may _hide_
undefined behaviour which is present in the code whether there is a cast
or not. If you call malloc() without a declaration in scope for it, you
always invoke undefined behaviour. The cast doesn't change that fact.
What it does do is stop the compiler from telling you about it.

No, it does not actually. This argument may have been relevant 10 years
ago, but it is no longer. Sure, it's not a required diagnostic in C89
mode, but any halfway decent compiler is able to warn about an
undeclared malloc() nowadays.

If you don't use the appropriate command line options to enable such
warnings, that's more of a problem than casting malloc results can ever be.

In short, I think this argument is stale, and is getting staler all the
time.

Best regards, Sidney
 
S

Sidney Cadot

magesh said:
Well I am not sure to measure upto u guys, my question may be redundnant.
My question is this, if people pretend with their own arguments
that casting malloc return may cause undefined behaviour, I would like
to know

Nobody is pretending that. Both sides agree that not including
<stdlib.h> before using malloc() is very wrong, it is this which causes
UB. Casting or not casting the result of malloc will not lead to
undefined behavior in itself.
double* p = malloc(8*sizeof(double));==>OK for some here because
implicit coversion is well enough
but why
double* p = (double*) malloc(8*sizeof(double));==>NOK for some.

It's not ok for some (most, actually) for what I'd like to call
stylistic reasons.
I assume that casting the malloc's return is just an indication for my
codevelopers who may see an assignement of p from a malloc a 500 or more
lines after my pointer declaration p.

If you can show me a plausible scenario for this, I'd welcome it. In
practice, malloc() results are almost always assigned to a typed pointer.
If we prentend that implicit conversion is safe

No reason to pretend, it is safe (for the result of malloc, anyway).
and the fact of casting
may cause UB due to probable alignement problems,

Not for a malloc() result, which is guaranteed to be properly aligned
for conversion to basically any type of pointer.
its a bit difficult to
understant why implicit conversion may be safer than an explicit more
than a matter of style.

It is claimed to be safer more from a code-maintenance point of view. In
this respect, some valid arghments do indeed exist.
Does compilers treat them differently?

As far as I know, there are no circumstances where x=y (with x of type
T* and y of type void*) yields a different semantics than x=(T*)y ; if
this is true, it is probable that any real-life compiler will treat
these equivalently.

Best regards,

Sidney
 
D

Dan Pop

In said:
informed opinion); and thank heaven for that, 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.

Sooner or later, they're bound to discover that Mark McIntyre is clc's
resident idiot and Mr Plauger the author or coauthor of a number of
highly appreciated books about programming.

Of course, this doesn't mean that the former can't right or the latter
can't be wrong, merely that it is highly improbable.

Dan
 
S

Sidney Cadot

Daniel said:
On Thu, 29 Jan 2004 01:08:46 +0100,



When programming in C you have to rely on the semantics of C with regard
to pretty much anything.

Not at all. For example, I do not have to rely on the semantics of
trigraphs, since I avoid them like the plague.

Best regards, Sidney
 
S

Sidney Cadot

Daniel said:
On Thu, 29 Jan 2004 01:08:46 +0100,



Changing an (presumably unique) identifier name is a piece of cake unless
you use a mechanical typewriter for writing source code. But automatically
changing the multiply-used type of an object with a text editor is a bit
more difficult.

It is good to see we are in utter agreement :)

Best regards, Sidney
 
D

Dan Pop

In said:
To me, that sounds like a bizarre statement. Please elaborate.

The only *good* reason for renaming an identifier is because the original
name was improperly chosen. Hence my "bizarre" statement above.

Dan
 
R

Richard Bos

Sidney Cadot said:
No, it does not actually. This argument may have been relevant 10 years
ago, but it is no longer. Sure, it's not a required diagnostic in C89
mode, but any halfway decent compiler is able to warn about an
undeclared malloc() nowadays.

And a halfway decent compiler _should_ not warn about problems you have
explicitly cast away.

Richard
 
S

Sidney Cadot

Holger said:
Occasionally I use explicit casts in that case, too, to silence
over-paranoid compilers ("It's my intention to be unprecise, so shut
up!"). In full awareness that it could introduce serious unwarned bugs
when the intVar is later changed to a longVar without modifying the
cast, when the type is not abstracted by a typedef. But that's another
thing than to not rely on it. To not rely on it has something of to
not trust its correctness of implementation or the correctness of the
rules themself.

Sure, ok. I rely on my compiler to follow the defined semantics, sure,
but I am in disagreement with some semantics, so I avoid relying on
them. Not because of distrust, but because of dislike.

In this respect, implicit void*-to-any* conversion, implicit
float-to-int conversion, and use of trigraphs are in the same "don't do
this" category, in my book.
Why exactly do you think that the float-to-int conversion is
unreasonable?

Because the conversion is inherently impossible to do right without loss
of information, for the mathematical objects that underly floats and
integers.

There's a clear distinction between integers and floats for me, which is
that, within range, the integers behave exactly like their mathematical
cousins. This is not true for floats, they are inherently an
approximation, which I /always/ keep in mind when working with them. For
this reason, I'm not much bothered by int-to-float conversions.
Do you think that an explicit conversion is "more correct" than an
implicit one? I'm quite sure that any existing conforming compiler
will produce exactly the same result in intVar for both cases.

They are semantically equivalent, but not stylistically.
Why exactly do you think that the void*-to-any* conversion is
unreasonable? What exactly could go wrong in the implicit semantics?

There's not so much wrong with void*-to-any* conversion, other than the
fact that it may be done implicitly. This, in my (unpopular) opinion,
allows for what I consider "sloppy typing":

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

I firmly believe that the right-hand-side expression should be converted
to the proper type (double *) before doing /anything/ with it (including
assigment). But I am probably alone in thinking that, in this particular
crowd.
Did you have any situations where you experienced the failure of the
implicit conversions (in both int and void), which you successfully
cured with an explicit cast? And that you could blame on the
semantics, not on a broken non-conforming compiler?

No. My style comes from armchair reasoning, not bad experiences.
Can you give another one that does not fit into one of these three?

I think that for a pointer d, the types of d and *d are relevant in any
context where it is used, and I believe there are more than three
contexts. But then, you probably meant something more specific.

Best regards,

Sidney
 
M

magesh

Sidney said:
Nobody is pretending that. Both sides agree that not including
<stdlib.h> before using malloc() is very wrong, it is this which causes
UB. Casting or not casting the result of malloc will not lead to
undefined behavior in itself.

I completely agree with the fact that proper header files should be
included, I would be amazed a proper C file that never calls a function
from stdlib, so normal programmers include them, if they give attention
to warnings from the compiler or else this thread is not meant for them.
It's not ok for some (most, actually) for what I'd like to call
stylistic reasons.

Thats what I think, but I agree with fact that unnecessary casts may
fool the compiler and prevent from warning, if not properly used.
If you can show me a plausible scenario for this, I'd welcome it. In
practice, malloc() results are almost always assigned to a typed pointer.

declaration of p 1000 lines before.
1001: p= malloc(sizeof(*p)*10);
or
those who don't care of memory
1001: p= malloc(1024);

could you tell me what type is p, while u are going through just this
part of ur code.

1001: p= (int*)malloc(sizeof(int)*10);

Thought it appears newbie ,I think this is more explicit!

Reagrding code maintenance, the other solution p= malloc(sizeof(*p)*10);
may be easy to change the type of p without changing the malloc line in
ur code, after that?? the fact that the type of p has changed may have
more impact on other lines where u use them, than those on one malloc
statement!!!

No reason to pretend, it is safe (for the result of malloc, anyway).



Not for a malloc() result, which is guaranteed to be properly aligned
for conversion to basically any type of pointer.



It is claimed to be safer more from a code-maintenance point of view. In
this respect, some valid arghments do indeed exist.



As far as I know, there are no circumstances where x=y (with x of type
T* and y of type void*) yields a different semantics than x=(T*)y ; if
this is true, it is probable that any real-life compiler will treat
these equivalently.
Yep thats what I expect too.
Best regards,

Sidney
Thanks for ur reply,
regards,
magesh
 
D

Dan Pop

In said:
No, it does not actually. This argument may have been relevant 10 years
ago, but it is no longer. Sure, it's not a required diagnostic in C89
mode, but any halfway decent compiler is able to warn about an
undeclared malloc() nowadays.

If you don't use the appropriate command line options to enable such
warnings, that's more of a problem than casting malloc results can ever be.

In short, I think this argument is stale, and is getting staler all the
time.

Try a reality check: how many newbies have you seen enabling such
warnings when they show the way they compiled their code (quite often,
people posting here show their compilation command line)?

And keep in mind that this discussion is focused on newbies, experienced
programmers have already defined their preference pro or con casting
void pointers and it is not this thread that is going to make them change
their minds (you will keep casting when this discussion is over, I will
keep avoiding such casts as the plague).

Dan
 
C

CBFalconer

Dan said:
The only *good* reason for renaming an identifier is because
the original name was improperly chosen. Hence my "bizarre"
statement above.

Names are originally chosen to make sense to the originator, at
that time. There are many occasions for revision, most of which
are for additional clarity or distinguishment. I keep a utility
around to make mass multiple identifier changes across multiple
files in single passes, and find it very useful at times.

The purpose of the software, the identity of the originator, and
the time are all subject to change, so "improper" is not the
appropriate description.
 

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

No members online now.

Forum statistics

Threads
474,139
Messages
2,570,806
Members
47,352
Latest member
Maricruz09

Latest Threads

Top