why is casting malloc a bad thing?

M

Mark McIntyre

Hm?

If the alignment is incorrect the conversion is invalid.

But its impossible for it to be incorrect. The C Standard says so. If
your h/w platform can't guarantee it, then you can't implement C
there.
 
S

Severian

But its impossible for it to be incorrect. The C Standard says so. If
your h/w platform can't guarantee it, then you can't implement C
there.

I agree. I worked on a platform years ago that crashed if you accessed
any data type on a non-platform-natural boundary.

At the time -- working on a real world project -- this caused a load
of grief. I felt that the implementation should have provided the
required converions, and some kind of (compile time or run time)
warning that the code code could be inefficient, rather than simply
crashing during execution.

It's not exactly an easy problem for compiler writers, though.

- Sev
 
E

E. Robert Tisdale

Martin said:
<OT>
C++ has a standardized way to interface with C code.
</OT>

A common misconception.
C++ only has a mechanism (extern "C")
to *help* with linkage.
Neither C or C++ specifies interoperability.
In particular, any two different compilers
(even two different C compilers)
may use a different representation for built-in types,
may use a different protocol to pass arguments and return values,
etcetera.
 
P

Peter Nilsson

But its impossible for it to be incorrect.
The C Standard says so. ...
[/QUOTE]

I'm sure Plauger is more than aware of what the C standard(s) say on the
issue! ;)

The return value for [re|c|m]alloc is correctly aligned for all types,
however, in general, the conversion itself in general is not guaranteed to
be aligned...

char c[sizeof(double)];
void *vp = c;
double *dp = vp; /* potential UB */


Severian said:
I agree. I worked on a platform years ago that crashed if you accessed
any data type on a non-platform-natural boundary.

They are not uncommon.
At the time -- working on a real world project -- this caused a load
of grief. I felt that the implementation should have provided the
required converions, and some kind of (compile time or run time)
warning that the code code could be inefficient, rather than simply
crashing during execution.

Implementations are quite limited in being able to repair the damage of bad
source code and practices (see above example). Do you have examples of what
the 'required conversions' should be, and the contexts in which they might
be 'useful'?
It's not exactly an easy problem for compiler writers, though.

Quite! :)
 
P

Peter Nilsson

Jack Klein said:
By and large, the phrase "style issue" is a whine of unprofessional
and/or incompetent programmers. ...

You left out a slur on business acumen.
 
A

Allin Cottrell

P.J. Plauger said:
Next step after nonsense -- bullshit. See 6.3.2.3, para. 7.

I seems to me that Mark McIntyre is right. The para 7 cited by P.J.
Plauger says:

"A pointer to an object or incomplete type may be converted to a pointer
to a different object or incomplete type. If the resulting pointer is not
correctly aligned for the pointed-to type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal to
the original pointer. [...]"

Para 1 of the same section says:

"A pointer to void may be converted to or from a pointer to any incomplete
or object type. A pointer to any incomplete or object type may be converted
to a pointer to void and back again; the result shall compare equal to the
original pointer."

So: para 1 says the void -> double pointer conversion is guaranteed to
produce a correct "round trip", while para 7 states that pointer conversion
*in general* will fail to produce a correct round trip in the case of
misalignment. It follows that misalignment is stipulated to be
impossible in the void -> double case.
 
S

Severian

I'm sure Plauger is more than aware of what the C standard(s) say on the
issue! ;)

The return value for [re|c|m]alloc is correctly aligned for all types,
however, in general, the conversion itself in general is not guaranteed to
be aligned...

char c[sizeof(double)];
void *vp = c;
double *dp = vp; /* potential UB */
They are not uncommon.

I know better now; this was ca. 1990.
Implementations are quite limited in being able to repair the damage of bad
source code and practices (see above example). Do you have examples of what
the 'required conversions' should be, and the contexts in which they might
be 'useful'?

Well, after we had fixed all the crappy code, we found a compiler
option that would include runtime code to work around alignment
errors. We pulled the original code and ran it; it was something like
40x slower than the fixed code.

I learned a lot that year!

- Sev
 
R

Richard Heathfield

Allin said:
I seems to me that Mark McIntyre is right.

It seems to /me/ that they are both right, because they are answering
different questions. Mark quite rightly assumes that nobody would be so
stupid as to attempt to perform a conversion such as:

char buf[] = "12345.678";
void *p = buf;
double *d = p; /* Don't Do This */
printf("%f\n", *d); /* And REALLY REALLY Don't Do THIS */

Whereas P J Plauger quite rightly assumes that some people /would/ be so
stupid.

If my supposition is true, it could certainly explain why they are both so
convinced they're correct. It would also suggest that Mr Plauger owes Mr
McIntyre and Mr Klein an apology. It is quite plain that neither Jack nor
Mark spoke nonsense, if one only takes a few seconds out to work out the
logic behind their answers.

Note, also, that the cast (remember that?) doesn't help in this situation.
If you try to convert an undoublypointery thing into a doublypointerything
by going via void *, the cast will not magically supply this conversion for
you.
 
P

P.J. Plauger

If my supposition is true, it could certainly explain why they are both so
convinced they're correct. It would also suggest that Mr Plauger owes Mr
McIntyre and Mr Klein an apology.

Or conversely. The bald statements they made were flat wrong.
It is quite plain that neither Jack nor
Mark spoke nonsense, if one only takes a few seconds out to work out the
logic behind their answers.

I understood their logic -- it was incomplete and they were wrong.
Note, also, that the cast (remember that?) doesn't help in this situation.
If you try to convert an undoublypointery thing into a doublypointerything
by going via void *, the cast will not magically supply this conversion for
you.

My point exactly.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
P

pete

Or conversely. The bald statements they made were flat wrong.
I understood their logic -- it was incomplete and they were wrong.


My point exactly.

Do you realize that, they were talking about the void pointer
value returned by malloc, as per the subject line of this thread ?
 
P

P.J. Plauger

Do you realize that, they were talking about the void pointer
value returned by malloc, as per the subject line of this thread ?

Looked to me like they were wandering a bit afield of that subject.
Certainly the statements that set me off were pure and unqualified.
But even there they're wrong:

double *pd = malloc(1);

There's no requirement that a malloc call return a pointer
properly aligned for double if the object being allocated is
too small to represent a double. So doctrinaire statements
about the validity of the implicit pointer conversion are
still wrong.

-----

But all this is a red herring. Adding a double cast won't fix the
problem of an improperly aligned void pointer. The brouhaha over
casting void pointers stems from the fact that the C committee
chose to recycle the existing C++ notation for void pointers and
intentionally gave them different semantics. We did a similar
thing with const and with function prototypes. Thus, the C
committee is partly to blame for the subtle dialect differences
between two languages that have an otherwise broad common base.

You can pretend that C++ doesn't exist, or that any matters
C++ are OT here, but that's sticking your head in the sand.
The observable fact is that *many* shops that use C mix it on
a daily basis with C++. Yes, you can ghettoize the two to a
large extent by using extern "C" to communicate between functions
written in the different languages. That's a good discipline
that often does the job. Nevertheless, there are cases where it
makes good project sense to maintain some code in the common
dialect that C and C++ share. That dialect is not bastard and
it is not crippled. Those who try to banish it are, IMO, simply
being silly.

I have no trouble with silliness in most contexts, being silly
about certain issues quite often myself. But I believe it does
a disservice to the lurkers on this newsgroup who are trying
to get educated. They at least deserve a more open consideration
of tradeoffs.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
J

Jeremy Yallop

P.J. Plauger said:
There's no requirement that a malloc call return a pointer
properly aligned for double if the object being allocated is
too small to represent a double.

There is such a requirement. The standard (both C89 and C99) is a bit
unlcear on this, but defect report #075 is unequivocal:

Question
Item 12 - alignment of allocated memory

Is a piece of memory allocated by malloc required to be aligned
suitably for any type, or only for those types that will fit into
the space? For example, following the assignment:
void *vp = malloc(1);
is it required that (void *)(int *)vp compare equal to vp (assuming
that sizeof(int) > 1), or is it permissible for vp to be a value
not suitably aligned to point to an int?

Response

Subclause 7.10.3 requires allocated memory to be suitably aligned
for any type, so they must compare equal.
<http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_075.html>

Jeremy.
 
P

P.J. Plauger

There is such a requirement. The standard (both C89 and C99) is a bit
unlcear on this, but defect report #075 is unequivocal:

Question
Item 12 - alignment of allocated memory

Is a piece of memory allocated by malloc required to be aligned
suitably for any type, or only for those types that will fit into
the space? For example, following the assignment:
void *vp = malloc(1);
is it required that (void *)(int *)vp compare equal to vp (assuming
that sizeof(int) > 1), or is it permissible for vp to be a value
not suitably aligned to point to an int?

Response

Subclause 7.10.3 requires allocated memory to be suitably aligned
for any type, so they must compare equal.
<http://std.dkuug.dk/JTC1/SC22/WG14/www/docs/dr_075.html>

Sigh. Guess I was out of the room when that one went through, or I
would have protested it. The C committee was clear enough when we
discussed our intent for malloc many years ago. Too bad the words
ended up 'a bit unclear' and the intent got reversed in response to
a DR. But so be it.

So the quibble continues. None of which alters the original bald statements
that started this subthread:

-----
But its impossible for it to be incorrect. The C Standard says so. If
your h/w platform can't guarantee it, then you can't implement C
there.
-----

I suppose you *can* see the malloc references in all this, but I
confess they're invisible to me.

And the fact remains that the C committee made it permissible to omit
the cast on a malloc call in order to grandfather a gazillion lines
of code with malloc calls written before we strengthened type checking
in C. We did so knowing we were blowing a hole in the type checking
system we cribbed from C++.

If you write malloc calls without casts, it's not because it's
necessarily good programming practice but because your grandfather did.

P.J. Plauger
Dinkumware, Ltd.
http://www.dinkumware.com
 
C

Christian Bau

Allin Cottrell said:
I seems to me that Mark McIntyre is right. The para 7 cited by P.J.
Plauger says:

"A pointer to an object or incomplete type may be converted to a pointer
to a different object or incomplete type. If the resulting pointer is not
correctly aligned for the pointed-to type, the behavior is undefined.
Otherwise, when converted back again, the result shall compare equal to
the original pointer. [...]"

Para 1 of the same section says:

"A pointer to void may be converted to or from a pointer to any incomplete
or object type. A pointer to any incomplete or object type may be converted
to a pointer to void and back again; the result shall compare equal to the
original pointer."

So: para 1 says the void -> double pointer conversion is guaranteed to
produce a correct "round trip", while para 7 states that pointer conversion
*in general* will fail to produce a correct round trip in the case of
misalignment. It follows that misalignment is stipulated to be
impossible in the void -> double case.

That is wrong. double* -> void* -> double* is guaranteed to "work" -
except in the case where the double* is not correctly aligned in which
case you had undefined behavior before you even started!

Misalignment is impossible in the case where (void* -> double* is
defined because the void* had correct alignment), it is quite possible
in the case where (void* -> double* is undefined because the pointer is
not properly aligned).
 
S

Sidney Cadot

P.J. Plauger said:
If you write malloc calls without casts, it's not because it's
necessarily good programming practice but because your grandfather did.

I'm gonna have myself a t-shirt made with that line :)

Regards,

Sidney
 
R

Richard Heathfield

Sidney said:
P.J. Plauger said:
If you write malloc calls without casts, it's not because it's
necessarily good programming practice but because your grandfather did.

I'm gonna have myself a t-shirt made with that line :)

Like most good tee-shirt slogans, it's simply not true. I write malloc calls
without casts because I think the casts do nothing good, and can hide bugs.
Furthermore, neither my father nor my grandfather wrote C programs.
 
E

E. Robert Tisdale

Richard said:
Like most good tee-shirt slogans, it's simply not true.

Wrong!
Tee-shirts *never* lie.
I write malloc calls without casts
because I think the casts do nothing good and can hide bugs.

You only need to accept the fact that you're just wrong.
 
R

Richard Heathfield

E. Robert Tisdale said:
Wrong!
Tee-shirts *never* lie.

If that's a tee-shirt slogan, it simply proves my point.
You only need to accept the fact that you're just wrong.

I will be perfectly willing (as my posting history shows) to accept that I'm
wrong if it can be shown that I am in fact wrong. So far, however, you have
not shown me to be wrong.
 

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,770
Messages
2,569,583
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top