Common misconceptions about C (C95)

S

spinoza1111

The traditional bug that not casting malloc() catches is when malloc()
is not declared (because the relevant #include is omitted) and thus
defaults to returning int.  C's strong typing would normally catch
that error, but is defeated by the cast.  That was why I used "int" in
my example.

That is completely absurd. I'll make a mistake in case I made a
mistake.
When you haven't made that mistake, the cast makes no difference
either way in terms of type safety.

It also seemed to me that Spinoza was asserting that casts are in
general a way to enforce strong typing, and I wanted to refute that.

I wasn't. C is a type-unsafe language, and jack shit can be enforced
in it. However, competent programmers when forced at gunpoint to use C
by criminals use cast in protest, primarily to document the intent of
their code for a post-C posterity to show that they haven't been
rendered completely mindless.

THE TRUTH IS THAT ALL PEOPLE ON EARTH ARE PUSHED BY TWO MEN INTO
PATTERNS THAT PLEASE THEM. THE PATTERNS SPELL OH NO NO NO BUT IT IS
NOT ENOUGH TO WRITE SYMBOLS. YOU MUST DO THE RIGHT ACTS WITH YOUR
BODY.

- Jenny Holzer, Laments
 
I

Ian Collins

Herbert said:
C is NOT C++.

It is considered errornous to cast the result of any function that
returns a pointer. That includes malloc, calloc, realloc because it
will produce bugs.

That should be "It is considered erroneous to cast the result of any
function that returns a void pointer".
So since that more than 15 years it is good practise to use prototypes
and never ever cast the returnvalue of functions returning some other
value than int.

That doesn't really parse. Why should a function returning int be special?
 
K

Keith Thompson

Herbert Rosenau said:
No, it will not.

The compiler will complain if p is not of type struct foo * (unless
it's of type void*).

I'm certainly not saying that the cast is a good idea, but *if*
you're going to insist on using the type name in the argument,
casting to a pointer to the same type can catch certain errors.
 
K

Keith Thompson

Herbert Rosenau said:
Naiva spots crap once again.

I think you mean "spouts". (I don't generally point out spelling
errors, but this one pretty much reverses the meaning of the
sentence.)
Even when you really have no other chance in C++ to use malloc you
must avoid casting in C - even as in C++ you can't - but for that you
must learn C++ and how to write C in C++ syntactically right.

What do you mean you *must* avoid casting?

If you're going to use malloc() in C++ (and assign the result to a
pointer of type other than void*), you need the cast.

The same cast is IMHO poor style in C, but it's not invalid. As long
as you get the types right (which includes keeping them right as the
code is maintained), the cast is perfectly legal.

I disagree with jacob on the importance of writing C that's also
valid C++; in my opinion, it's almost never necessary or sensible.
But in the rare cases where you really do need to compile the
same source as C and as C++, yes, you do need to cast the result
of malloc. (Either that, or use a bunch of "#ifdef __cplusplus"
directives, but IMHO the cast is cleaner.)
But you proves once again that your know ledge of both C and C++ is
not good enough to gget one of both right.

Yes, we know that you spams constantly for a product that you have the
sources under control - but you've not written but adoped.

jacob freely acknowledges that lcc-win is based on lcc; Google
"lcc-win" and take a look at the first hit. My understanding is that
he's re-written substantial parts of it himself. Your statement that
he's "not written but adop[t]ed" it implies something nefarious that,
as far as I can tell, has no basis in reality. And I fail to see
how that's relevant anyway. Perhaps when jacob says something you
dislike, you feel the need to bring up something else about jacob
that you dislike. That's not exactly constructive.

It may seem odd that I'm defending jacob. It's simply because,
in this instance, he's (mostly) right and you're wrong.

(jacob, if you're reading this, I just noticed a typo on
<http://www.cs.virginia.edu/~lcc-win32/>: "if you use it
professionally you have to *have to* buy a licence".)
 
K

Keith Thompson

Herbert Rosenau said:
Nonesense! The casts are superflous and errornouse!

Superfluous, yes. Erroneous, no.
Instead to avoid
an error you are creating one - hiding an error by cast is not the
right way to remove it. You does in no way prevent a type error - but
generates one instad by casting the return value.

Casting the result of malloc or calloc can hide an error in some
cases. It does not *create* an error. This:

int *ptr = (int*)malloc(sizeof(int));

is valid code, though IMHO poor style.

You weaken your case by falsely claiming that the cast is incorrect.
And calloc is only in single case the right function: you'll allocate
a char array. In any other case you'll create an error, because
setting another tye as char bytewise to 0 will produce unexpected
results when the implementation uses padding bits for values other
than bytes. That makes calloc still useless.

All-bits-zero is guaranteed to be a representation of 0 for all
integer types. This guarantee isn't in the C90 or C99 standard; it
was added in one of the Technical Corrigenda, and appears in N1256
6.2.6.2p5. I believe it's safe to rely on this for all existing C
implementations (which is why the committee felt safe in adding this
guarantee to the standard).

[...]
 
E

Eric Sosman

Herbert said:
There is a rule you should learn: never ever cast except you KNOWs
exactly WHY you must cast. However when you knows not exactly why but
you means you must cast then use a good book, the clc FAQ, or this
group to get more information. Be sure most when not always you'll end
up with 'no cast needed'.
[...]

One possible "WHY" is "for documentation, for emphasis, to
highlight a conversion that would occur even without the cast but
might escape the notice of a casual reader." Such cases are rare,
but they do occur now and then.

The conversion of malloc()'s result to AnyType* is not one
of those cases.
 
K

Keith Thompson

Keith Thompson said:
Superfluous, yes. Erroneous, no.

Unless you mean something else by the word "erroneous". It usually
means invalid or illegal. What do you mean by it?
 
R

robertwessel2

Nonesense! The casts are superflous and errornouse! Instead to avoid
an error you are creating one - hiding an error by cast is not the
right way to remove it. You does in no way prevent a type error - but
generates one instad by casting the return value.


On the contrary. Having the function invoked return a pointer of the
correct type allows the compiler to check the assignment. The point
of the macro is to bind the allocation to the casting of the void
pointer, and not allowing the programmer to make an error doing that
manually. Thus making the function more typesafe, like C++'s new.

As I mentioned, it does not solve the problem of a missing prototype
for the allocation function, although if these macros were in stdlib.h
along with the base allocation functions, the problem would be no
worse than with an uncasted raw malloc (IOW, you'd get an error
converting the implicit int returned from the unprototyped CALLOC_TYPE
to a pointer).

And calloc is only in single case the right function: you'll allocate
a char array. In any other case you'll create an error, because
setting another tye as char bytewise to 0 will produce unexpected
results when the implementation uses padding bits for values other
than bytes. That makes calloc still useless.


What part of "(and probably malloc versions as well)" did you miss?

By that: most halfways modern implementations will still overwrite the
allocated block to overwrite content not written by the application
calling malloc for security. That makes calloc superflous and
errornous too.


Really? Presumably the C compilers I use don't qualify as "halfways
modern," because *none* of them do what you claim when not in debug
mode.
 
I

Ian Collins

On the contrary. Having the function invoked return a pointer of the
correct type allows the compiler to check the assignment. The point
of the macro is to bind the allocation to the casting of the void
pointer, and not allowing the programmer to make an error doing that
manually. Thus making the function more typesafe, like C++'s new.

But all that's being checked is that you have written the macro
correctly. The casting of the void pointer is still superfluous.
 
R

robertwessel2

But all that's being checked is that you have written the macro
correctly.  The casting of the void pointer is still superfluous.


One of us is missing something. The suggested macro allows
typechecked allocation similar to:

int *pi;
int i;
char *pc;
pi = CALLOC_TYPE(int) /* OK */
i = CALLOC_TYPE(int) /* Diagnostic - conversion of int * to int */
pc = CALLOC_TYPE(int) /* Diagnostic - conversion of int * to char
* */

And if the allocation macros are included in stdlib.h, then using them
without the include is relatively safe as well (at least as safe as
using malloc without a cast).
 
S

spinoza1111

C is NOT C++.

It is considered errornous to cast the result of any function that
returns a pointer. That includes malloc, calloc, realloc because it
will produce bugs.

There is one exception: you use a K&R 1 compiler. But since C is a
language that knows prototypes it is clearly a bug to cast pointers
returned by a function. This faulty cast may end up in undefined
behavior.

Include the header that declares the prototypes.

In K&R 1 any function was returned int when nothing else was declared.
Since more than 15 years C was changed to have prototypes that will
declare what type comes back from a function - and since then it is
clearly bad practise to override the prototype with a faulty cast.

So never ever use x = (<type>) malloc(size); because when you goes
wrong by not #include <stdlib.h> you fails to serve the compiler the
right type malloc returns - that can end in converting an int that
malloc has not even set to an pointer because default converation says
that malloc returns int, not a pointer. That means that on some
implementations not the returned pointer but an int returned some time
prior by another function will get as source for cast.

"Here at Globo Gym we understand that ugliness and fatness are genetic
disorders, much like baldness or necrophilia, and it's only your fault
if you don't hate yourself enough to do something about it" - White
Goodman, Dodgeball

(1) So isn't it easier to just include stdlib?
(2) That way you can cast malloc
(3) And keep your program type safer in hack-o-rama: it would seem
that safe praxis is more important in a bozo language like C
(4) And that way you have more time for Nazi camp, breaking up
Salvation Army meetings, and necrophilia
 
S

spinoza1111

But all that's being checked is that you have written the macro
correctly.  The casting of the void pointer is still superfluous.

"Superfluity" is not an argument since in a language like C it's
important to document intent. Furthermore, here's Galileo on the
superfluity of superfluity:

"I am (indeed) unwilling to compress philosophical doctrines into the
most narrow kind of space and to adopt that stiff, concise, graceless
manner, that manner bare of any adornment which pure geometricians
call their own, not uttering a single word that has not been given to
them by strict necessity... I do not regard it as a fault to talk
about many diverse things, even in those treatises which have only a
single topic ... for I believe that what gives grandeur, nobility, and
excellence to our deeds and inventions does not lie in what is
necessary – though the absence of it would be a great mistake – but
what is not."

In other words, reason not the need.

Coding by shibboleth makes for UNREADABLE code. "Gee, why did this
bozo leave out the cast?" "He mighta left out stdlib". "You're
shitting me." "I would not shit thee for thou'rt my favorite turd."
 
I

Ian Collins

One of us is missing something. The suggested macro allows
typechecked allocation similar to:

int *pi;
int i;
char *pc;
pi = CALLOC_TYPE(int) /* OK */
i = CALLOC_TYPE(int) /* Diagnostic - conversion of int * to int */

That would give a diagnostic anyway.
pc = CALLOC_TYPE(int) /* Diagnostic - conversion of int * to char* */

I still don't see any advantage over the idiomatic

pc = calloc( i, sizeof(*pc) );

which doesn't requires changing of the type of pc changes.
 
N

Nick

Eric Sosman said:
Herbert said:
There is a rule you should learn: never ever cast except you KNOWs
exactly WHY you must cast. However when you knows not exactly why
but you means you must cast then use a good book, the clc FAQ, or
this group to get more information. Be sure most when not always
you'll end
up with 'no cast needed'.
[...]

One possible "WHY" is "for documentation, for emphasis, to
highlight a conversion that would occur even without the cast but
might escape the notice of a casual reader." Such cases are rare,
but they do occur now and then.

An example: in my interpreter (which is written in C), I have a function
that creates a new stack frame, which is used when calling a subroutine,
starting a loop etc. This returns a pointer to the stack frame
immediately above the one it's created which can be used to unwind the
stack back (this is particularly useful when "return" is issued inside a
loop in a function - you want to remove both the loop and the function
frames from the stack).

It's called once at program initiation to create a stack frame for the
program to execute inside. It will always return NULL there, because
there is no other frame. I don't need to keep this (if I did, I could
always use NULL away) because there is no sensible meaning to leaving
that frame. So when I call it, at that point in the flow, it's like
this: (void)New_Stack_Frame(NULL);
The conversion of malloc()'s result to AnyType* is not one
of those cases.

I still agree.
 
K

Keith Thompson

Gareth Owen said:
Occasionally, yes.

Really? Why? I'm geniunely curious.

If you really have a legitimate need to compile the same code as C
and as C++, I think you'd be the third such person I've seen here.
(One of the others was P.J. Plauger.)
Because, not casting has almost no benefit, and what you suggest is
considerably more work. Casting or not casting malloc is a piece of
coding practice, and nothing like as hard-and-fast-a-rule as it is made
out to be here. Restructuring a codebase merely to avoid it is not a
good use of my time.

I don't think you answered my question.

How would compiling C as C, C++ and C++, and linking things together
using ``extern "C"'' not satisfy your requirements at least as well
as compiling the same code as C and C++?

There are some fairly subtle differences between the two languages
(though none that are insurmountable). Personally, I prefer to
keep track of one set of language rules at a time.
 

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
474,008
Messages
2,570,268
Members
46,867
Latest member
Lonny Petersen

Latest Threads

Top