Re: Common misconceptions about C (C95)



On 2009-11-18, Michael Tsang <miklcct@xxxxxxxxx> wrote:
Ioannis Vranos wrote:

I have created a text available under GNU FDL 3 (Free Documenation
License) or later, regarding "Common misconceptions about C" (C95).


http://www.cpp-software.net/documents/free_documents/c_misconceptions.html


Any constructive comments/error corrections are welcome. :-)



Best regards,


10. Use of malloc without casting is considered a poor practice (it is an
error in C++). Cast it to suitable type instead.

Actually this recommendation is completely useless, if you don't have
enforcement from the compiler, or some tool like lint.

Without the cast being required due to a mandatory diagnostic, you and your
other programmers will not reliably stick to the above rule.

Even people who believe in the rule will screw up.

I've been trying to switch to the habit of adding the cast, but I find that
I keep forgetting!

So, by itself, this rule has less worth than a rule which says ``it is poor
practice to make some kind of mistake in your use of malloc'', because
it's essentially a rule which says ``it is poor practice to do something that
is often correct, and even considered a good idiom by some C programmers,
some of whom are experts, and for the violation of which there is no diagnostic
support in the standard language''.

But what /is/ poor practice is designing a programming language feature which
allows you to request dangerous conversions without having to provide a written
token that marks the places in the program where these conversions
are happening. You simply use the assignment operator between two expressions,
the same way like you could do in a typeless language between /any/ two
expressions. (E.g. a predecessor of C, like BCPL).

The void and void * types come from C++ which has a better rules for them.
It doesn't have the implicit conversion from void * to any object type,
and C++ doesn't have the silly (void) hack. (Someone should have had the
balls to uproot non-prototype declartions from C back in in 1989: boldly
removing something from a standard doesn't mean compilers can't continue to
support it).

C once had malloc which returned char *. There was nothing wrong with this; it
did not have to change. If anywhere at all, the void * type should have only
been used in the free and realloc functions for passing pointers down.

So, the thing to do is to eliminate the use of the void * type from your C
programs, at least in situations where it will likely be converted to another
type.

I recommend that interfaces which accept a generic pointer-to-anything continue
to be written to accept void * arguments, but when those pointers are returned,
they should be returned as unsigned char *.

Rationale: it is correct and sometimes useful to be able to treat any
object as an array of bytes (unsigned char *). If we don't know what a
pointer points to, but we do know that it points to an object, then
it's okay for that pointer to be a pointer to unsigned char *. We can
safely dereference that pointer to access a byte. Functions that call
malloc only to obtain a block of bytes should not have to do the cast
since any object already /is/ a block of bytes.

If the object is to be used as some other type, even as a char * string, then a
cast will be required. So, you don't need your rule 10: just design the API so
that code won't compile without the cast.
.



Relevant Pages

  • Re: Can I Trust Pointer Arithmetic In Re-Allocated Memory?
    ... You can't do pointer arithmetic on a void* value. ... qsort behaves in a manner consistent with its specification. ... actually works as advertised...but doesn't mean that the cast is ...
    (comp.lang.c)
  • Re: dynamic_cast does not work as specified
    ... then p is a pointer to an object of type SubThing. ... SubThing* via a C-style cast. ... virtual void ShowPURE; ... type-id must be a derived class of expression [note that the simple explanation could be ...
    (microsoft.public.vc.mfc)
  • Re: [RFC] timers, pointers to functions and type safety
    ... * they have callback of type void ... callback is called by the code that even in theory has no ... cast to unsigned long and cast back in the callback. ... number - not a pointer cast to unsigned long, not an index in array, etc. ...
    (Linux-Kernel)
  • Re: About casts (and pointers)
    ... > a cast). ... > the implementation's (void **) representation and length. ... Your sometype ** pointer is presumably pointing at ...
    (comp.lang.c)
  • Re: main function address
    ... |>>You can interpret it as an array of unsigned char and print the values ... |>If you can't cast it to void*, now can you cast it to unsigned char *? ...
    (comp.lang.c)