to cast or not to cast malloc ?

M

MSG

The answer is neither. Use macros.

#define ALLOC(size, type) ((type) *) malloc((size) * sizeof(type))
#define NEW(type, name, size) (type) * (name) = ALLOC((size), (type))

They are both [more] type-safe and concise.

Compare:

NEW(int, x, 1000);

to

int * x = (int*) malloc(sizeof(int) * 1000);


I'm sure someone must have "discovered" this before. Anyways HTH.

MSG
 
R

Richard Heathfield

MSG said:
The answer is neither. Use macros.

#define ALLOC(size, type) ((type) *) malloc((size) * sizeof(type))
#define NEW(type, name, size) (type) * (name) = ALLOC((size), (type))

They are both [more] type-safe and concise.

Compare:

NEW(int, x, 1000);

to

int * x = (int*) malloc(sizeof(int) * 1000);

If you must compare, at least compare to good code:

int *x = malloc(sizeof *x * n);
I'm sure someone must have "discovered" this before. Anyways HTH.

Yes, they're hardly new, I'm afraid.

Presumably you have equivalents for all the other functions returning a void
pointer? Not just the standard library functions (memchr, memset, bsearch,
calloc, realloc), but all the third-party libraries, too?

If not, you'd better get busy. When the /whole set/ is completed, fully
tested, and guaranteed by ISO to work correctly, I'll start using them.
Deal?
 
E

E. Robert Tisdale

Richard said:
If you must compare, at least compare to good code:

int *x = malloc(sizeof *x * n);

Both P. J. Plauger and Bjarne Stroustrup disagree with you.
It isn't good code.
It's a bad habit that was "grandfathered" into the standards
so that the standard wouldn't break all of the existing bad code.

Please reference recent articles in the comp.lang.c newsgroup.
 
C

Clint Olsen

Both P. J. Plauger and Bjarne Stroustrup disagree with you. It isn't
good code. It's a bad habit that was "grandfathered" into the standards
so that the standard wouldn't break all of the existing bad code.

Please reference recent articles in the comp.lang.c newsgroup.

I trust Steve Summit's opinion far more than I do yours, so the rest of us
will leave off the cast, thanks.

-Clint
 
A

Allin Cottrell

E. Robert Tisdale said:
Both P. J. Plauger and Bjarne Stroustrup disagree with you.
It isn't good code.
It's a bad habit that was "grandfathered" into the standards
so that the standard wouldn't break all of the existing bad code.

OK, this is my last posting on this topic (promise, I think).

First, my only objection to Richard's example is purely stylistic;
I find it clearer on the eye to write:

int *x = malloc(n * sizeof *x);

rather than

int *x = malloc(sizeof *x * n);

(There's something a little confusing about the two '*'s in close
proximity in the version Richard wote above.)

Second, leave Mr Stroustrup out of it. I'm sure he is (or was) an
expert C programmer, but his commitment to C++ renders him an
unreliable witness in this case (C++ requires that the return of
malloc be cast to the type at issue -- although, as others have
noted, use of malloc is not really idiomatic in C++ anyway).

That leaves the reference to Mr Plauger, who is assuredly an
expert in C. In previous discussions of this point on clc we
can distinguish Plauger1 and Plauger2.

Plauger1 offers the argument that in some special contexts there
is a need for C code that can also be compiled as C++. In that
case, as most participants in the debate have acknowledged,
sticking a cast in front of the malloc return is OK, so long as
we can be sure that stdlib.h has been included. However, this
special case hardly justifies the notion that casting the
return from malloc is in general "good C practice".

Plauger2 (I think) goes further, and bemoans the fact that
automatic conversion from (void *) to (whatever *) was ever
accepted into standard C. To Plauger2 (who may not correspond
to the real P.J. Plauger, but apparently does correspond to
E.R. Tisdale) I say, "Get over it!" Such automatic conversion
_is_ part of ISO/ANSI standard C and has been for well over a
decade. Good C programing is defined in relation to the
actually existing standard, not some people's notion of what
the C standard ought to have been.
 
S

Sidney Cadot

Allin said:
Plauger2 (I think) goes further, and bemoans the fact that
automatic conversion from (void *) to (whatever *) was ever
accepted into standard C. To Plauger2 (who may not correspond
to the real P.J. Plauger, but apparently does correspond to
E.R. Tisdale) I say, "Get over it!" Such automatic conversion
_is_ part of ISO/ANSI standard C and has been for well over a
decade.

So are trigraphs. The "because we can" argument is fundamentally
unsound, IMHO. There are several good reasons for not casting malloc
results, but the fact that C /allows/ them to be not casted is not one
of them.
Good C programing is defined in relation to the
actually existing standard, not some people's notion of what
the C standard ought to have been.

Which one, C89 or C99? Because with C99, the stdlib.h argument (which is
weak already because of modern compilers) goes entirely out the window.

Best regards,

Sidney
 
E

E. Robert Tisdale

Allin said:
Plauger2 (I think) goes further, and bemoans the fact that
automatic conversion from (void *) to (whatever *)
was ever accepted into standard C.
To Plauger2 (who may not correspond to the real P.J. Plauger
but apparently does correspond to E. R. Tisdale) I say, "Get over it!"

Such automatic conversion _is_ part of ISO/ANSI standard C
and has been for well over a decade. Good C programing is defined
in relation to the actually existing standard,
not some people's notion of what the C standard ought to have been.

No.
The standard allows programmers to do all kinds of things
that are *not* necessarily "good programming practice".
C is *not* Ada. C programmers are given a cocked and loaded fire arm
with the safety turned off.
All they need to do is point it at the remaining foot and blow it off.
Good programming practice is the exercise of [self]discipline.

According to Plauger, the implicit conversion from *void
to any other pointer type is the result of poor programming practice
and a lack of [self]discipline. The were compelled to include it
in the standard because so much bad code had already been written.
 
A

Allin Cottrell

Sidney said:
So are trigraphs. The "because we can" argument is fundamentally
unsound, IMHO. There are several good reasons for not casting malloc
results, but the fact that C /allows/ them to be not casted is not one
of them.

The actual nature of C makes the cast redundant. The insertion
of redundant casts -- not their omission -- requires some sort
of special justification. This is my point.
Which one, C89 or C99? Because with C99, the stdlib.h argument (which is
weak already because of modern compilers) goes entirely out the window.

Suppose "the C standard" is some sort of weighted average of C89 and
C99, the weights depending on the context of the discussion. As the
weight on C99 approaches 1.0, the stdlib.h argument approaches
negligibility. The argument that redundant casts are best
avoided retains its full force. The Plauger1 argument that some
code may have to be compiled as C++ retains its orthogonality to
the issue of good C practice. The notion that "we really ought
to have to cast the malloc return and it's a shame we don't"
retains its irrelevance.
 
J

Jack Klein

Both P. J. Plauger and Bjarne Stroustrup disagree with you.
It isn't good code.
It's a bad habit that was "grandfathered" into the standards
so that the standard wouldn't break all of the existing bad code.

Please reference recent articles in the comp.lang.c newsgroup.

Another one of your utterly foolish replies, I'm afraid. Since there
was no void or pointer to void in K&R C, malloc() in those days was
defined as returning a pointer to char. All calls to malloc() that
allocated memory to be used for other types than char required the
cast.

So it is quite obvious that there was nothing to "grandfather" in this
regard.

As for Stroustrup, note that C++ allows the implicit conversion TO
pointer to void FROM pointer to any other object type, as does C, just
not the reverse. The reasoning for this strikes me as a little
suspect. Unlike, I hasten to add, most of Dr. Stroustrup's other
design decisions in the development of C++. Also note that he has
proposed allowing the void pointer to object pointer conversion in a
future version of the C++ standard.

Plauger gave very specific reasons for his preference, and it really
has nothing to do with C and everything to do with C++.
 
C

CBFalconer

Allin said:
.... snip ...

Plauger2 (I think) goes further, and bemoans the fact that
automatic conversion from (void *) to (whatever *) was ever
accepted into standard C. To Plauger2 (who may not correspond
to the real P.J. Plauger, but apparently does correspond to
E.R. Tisdale) I say, "Get over it!" Such automatic conversion
_is_ part of ISO/ANSI standard C and has been for well over a
decade. Good C programing is defined in relation to the
actually existing standard, not some people's notion of what
the C standard ought to have been.

I never noticed that! If true, Trollsdale has learned yet another
evil trick. At any rate the only one who can say for sure is P.J.
Plauger, who should object violently to any such happenings.
Impersonation is not looked upon with favor by ISPs.

In fact, the very continued presence of Trollsdale here tends to
argue against his having practiced such a trick.
 
R

Richard Heathfield

Allin said:
OK, this is my last posting on this topic (promise, I think).

First, my only objection to Richard's example is purely stylistic;
I find it clearer on the eye to write:

int *x = malloc(n * sizeof *x);

rather than

int *x = malloc(sizeof *x * n);

So do I! :) Again, I've been caught by my tendency to edit the original
code as little as possible (I don't like to insist that people do things my
way).

<snip>
 
R

Richard Heathfield

E. Robert Tisdale said:
Both P. J. Plauger and Bjarne Stroustrup disagree with you.

I'm sure both gentlemen are capable of speaking for themselves.
It isn't good code.

Your opinion of what constitutes good code is of little or no interest to
me. I prefer the opinion of C experts. Mr Stroustrup is, of course, a C++
expert; Mr Plauger is in fact a C expert, and I would point out that he has
most certainly /not/ said that omitting the cast constitutes bad style. It
is merely something he prefers not to do, for excellent reasons of his own.

<snip>
 
R

Richard Heathfield

E. Robert Tisdale wrote:

According to Plauger, the implicit conversion from *void

Plauger would say no such thing, for the very good reason that C does not
permit the dereferencing of a void object - so there is /no/ implicit
conversion from *void.
 
K

Keith Thompson

E. Robert Tisdale said:
The standard allows programmers to do all kinds of things
that are *not* necessarily "good programming practice".
C is *not* Ada.

In that sense, Ada isn't Ada either. I've seem some very ugly Ada
code. There is no programming language that makes it impossible, or
even particularly difficult, to write bad code. (Ada tries to make it
easier to write good code, but that's a topic for another newsgroup.)
 
K

Keith Thompson

Jack Klein said:
Since there was no void or pointer to void in K&R C, malloc() in
those days was defined as returning a pointer to char. All calls to
malloc() that allocated memory to be used for other types than char
required the cast.

On my old SunOS 4.1 system (circa 1990), malloc() is declared to
return char*, and the pre-ANSI C compiler issues a warning: "illegal
pointer combination" on an assignment of the result of malloc() to an
int*. Also, the man page for malloc() says:

Note: Always cast the value returned by malloc(), realloc(),
calloc(), memalign(), valloc() or alloca().

(advice that is, of course, no longer as good as it was at the time).

I wonder, though, if at least some pre-ANSI compilers were a bit lax
about pointer conversions. In particular, I wonder if they allowed
implicit conversions from char* to other object pointer types.
 
M

MSG

Richard Heathfield said:
MSG said:
The answer is neither. Use macros.

#define ALLOC(size, type) ((type) *) malloc((size) * sizeof(type))
#define NEW(type, name, size) (type) * (name) = ALLOC((size), (type))

They are both [more] type-safe and concise.

Compare:

NEW(int, x, 1000);

to

int * x = (int*) malloc(sizeof(int) * 1000);

If you must compare, at least compare to good code:

int *x = malloc(sizeof *x * n);
I'm sure someone must have "discovered" this before. Anyways HTH.

Yes, they're hardly new, I'm afraid.

Presumably you have equivalents for all the other functions returning a void
pointer?

Some of them.
Not just the standard library functions (memchr, memset, bsearch,
calloc, realloc), but all the third-party libraries, too?

Irrelevant (unless I don't understand what you are saying)
If not, you'd better get busy. When the /whole set/ is completed, fully
tested, and guaranteed by ISO to work correctly, I'll start using them.
Deal?

International law is to complicated to make this deal worthwhile :)

My point is that by using NEW instead of malloc directly, you

1. Save the typing
2. Make code more readable
3. Prevent size errors like

double * y = /* whatever */ malloc(sizeof(float) * 1000);
/* decided to change precision, forgot to change mallocs */
or
float * x = /* whatever */ malloc(sizeof(*x) * 1000);
double * y = /* whatever */ malloc(sizeof(*x) * 1000);
/* copied the line, forgot to change x (or type) */
or
float * x = /* whatever */ malloc(1000 * bla * foo / baz)
/* forgot sizeofs in all of the excitement */

4. Have the benefit of being able to easily change your mind
about casting depending on your compiler, language dialect, etc.

It's a win-win-win-win-win situation.

MSG

P.S. Too much ON-topic is boring me, so this thread of over
for me, unless Mr. E.R. Tisdale tells us why they mostly
gave up *Ada* in favor of C/C++ at NASA! (I know why, but
I'm curious about your esteemed opinion)
 
E

Emmanuel Delahaye

In said:
#define ALLOC(size, type) ((type) *) malloc((size) * sizeof(type))
#define NEW(type, name, size) (type) * (name) = ALLOC((size), (type))

They are both [more] type-safe and concise.

Compare:

NEW(int, x, 1000);

to

int * x = (int*) malloc(sizeof(int) * 1000);

What about:

#include <stdlib.h>

#define NEW(type, name, size) \
(type) * (name) = malloc (size * sizeof * (name))

#define DELETE(name)\
free (name), (name) = NULL

NEW (int, px, 1000);

if (px != NULL)
{
DELETE (px);
}
 
S

Sidney Cadot

Are you implying that ERT could be impersonating Mr. Plauger? That's a
very serious allegation; if you stand by it, you will need to back it
up. Even hinting at the possibility is possibly slanderous. Especially
in dealing with people of sometimes questionable standards (e.g. ERT's
well-documented quote-altering behavior) it is essential to keep to the
moral high ground.
The actual nature of C makes the cast redundant.

This is a bit vague for my taste. The cast is made superfluous by the
standard in typical-use cases, that's something more precise. However,
the standard (I'm talking about C99 now) also makes "return 0;" at the
end of main superfluous. Does that mean I'm going to follow suit? I
think not.

As to your use of the word "redundant": that is too strong for my taste.

malloc(50*sizeof(double))

and

(double *)malloc(50*sizeof(double))

have different types. Ergo, the cast has a function, with regard to this
expression, and it is not redundant.
The insertion of redundant casts -- not their omission --
> requires some sort of special justification. This is my point.

Yes. Over and over again, two justifications have been presented, by me
at least:

- making sure that your program is also conforming C++ (if you
want/need this for one reason or another).

- correcting the compiler's misconception about a pointer to an
allocated block of memory at the earliest possible convenience
(which means: prior to the pointer being used in any way,
for example, as the right-hand-side of an assignment).

For me, these are the justification.
Suppose "the C standard" is some sort of weighted average of C89 and
C99, the weights depending on the context of the discussion.

That sounds like a dangerous path to follow. The first problem is that
there exist no standards for weight values other than 0 and 1. The
second problem is that people can tune the weight to support their
opinion in any given situation. In essence, you're providing a knob that
one can turn to shift the goalposts.
As the
weight on C99 approaches 1.0, the stdlib.h argument approaches
negligibility. The argument that redundant casts are best
avoided retains its full force.

I object to your use of the word "redundant". It is fair to say that the
compiler will perform a conversion of the malloc result soon as a result
of the typical use pattern, where malloc() is used as the RHS of an
assignment, but that's something different entirely from saying the cast
is "redundant".
The Plauger1 argument that some
code may have to be compiled as C++ retains its orthogonality to
the issue of good C practice. The notion that "we really ought
to have to cast the malloc return and it's a shame we don't"
retains its irrelevance.

That's as explicit a restatement of the "because we can" argument as
they come. I whole-heartedly and sincerely disagree.

Best regards,

Sidney
 
R

Richard Heathfield

MSG said:
Richard Heathfield said:
MSG said:
The answer is neither. Use macros.

#define ALLOC(size, type) ((type) *) malloc((size) * sizeof(type))
#define NEW(type, name, size) (type) * (name) = ALLOC((size), (type))

They are both [more] type-safe and concise.

Compare:

NEW(int, x, 1000);

to

int * x = (int*) malloc(sizeof(int) * 1000);

If you must compare, at least compare to good code:

int *x = malloc(sizeof *x * n);
I'm sure someone must have "discovered" this before. Anyways HTH.

Yes, they're hardly new, I'm afraid.

Presumably you have equivalents for all the other functions returning a
void pointer?

Some of them.
Not just the standard library functions (memchr, memset, bsearch,
calloc, realloc), but all the third-party libraries, too?

Irrelevant (unless I don't understand what you are saying)

Either you think it's okay to have an implicit conversion from void * to
some object pointer type or other, or you think it isn't. If you think it
/is/ okay, then what are we arguing about? And if you think it /isn't/ okay
and wish to advocate a "fix", then - for that fix to be /useful/ - it
should surely apply to /all/ functions that return void *, not just one of
them?
International law is to complicated to make this deal worthwhile :)

The point is that you're never going to be able to provide similar solutions
for all the void *-returning functions in the world, because you'll never
even know what they all are.
My point is that by using NEW instead of malloc directly, you

1. Save the typing

Why not call it N, then? You'd save even more typing.
2. Make code more readable

I disagree; malloc is idiomatic, but NEW is not.
3. Prevent size errors like

double * y = /* whatever */ malloc(sizeof(float) * 1000);

But I don't make those errors, because I do:

T *p = malloc(n * sizeof *p);

which is always correct.
/* decided to change precision, forgot to change mallocs */
or
float * x = /* whatever */ malloc(sizeof(*x) * 1000);
double * y = /* whatever */ malloc(sizeof(*x) * 1000);
/* copied the line, forgot to change x (or type) */

That'll teach you to copy-and-paste without thinking.

or
float * x = /* whatever */ malloc(1000 * bla * foo / baz)
/* forgot sizeofs in all of the excitement */

4. Have the benefit of being able to easily change your mind
about casting depending on your compiler, language dialect, etc.

I already have that, because I already use a wrapper. Just not /your/
wrapper. Note that my wrapper does not include a cast.
It's a win-win-win-win-win situation.

So you say.
MSG

P.S. Too much ON-topic is boring me,

Then you're in the wrong newsgroup. comp.lang.c is all about on-topic.
so this thread of over
for me, unless Mr. E.R. Tisdale tells us why they mostly
gave up *Ada* in favor of C/C++ at NASA! (I know why, but
I'm curious about your esteemed opinion)

It's not clear what you mean. If you esteem my opinion, why not listen to
it? If you esteem Mr Tisdale's opinion, you don't know him well enough.
 
C

CBFalconer

Emmanuel said:
.... snip ...

What about:

#include <stdlib.h>

#define NEW(type, name, size) \
(type) * (name) = malloc (size * sizeof * (name))

#define DELETE(name)\
free (name), (name) = NULL

NEW (int, px, 1000);

if (px != NULL)
{
DELETE (px);
}


void *p[N], *t;
.....
t = p;
assert(M < N);
p[M] = NULL;
for (i = 0; i < M; i++) NEW(void, t, 10);
while (t) DELETE(*t++);

woops!
 

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,731
Messages
2,569,432
Members
44,835
Latest member
KetoRushACVBuy

Latest Threads

Top