(int *)(char *)expr

Wayne Throop throopw at rtp47.UUCP
Tue Oct 8 07:47:02 AEST 1985


Ah yes.  Casting pointers.  A favorite passtime for anyone (such as
myself) who uses an architecture where char *  has different format
from int *.  Something Guy Harris said on the subject aroused my
interest, and I'd like to expand on his point a bit.

> > A popular convention is to use the "(char *)0" definition.  This can
> > get confusing if your source code contains (int *)NULL.  Some (the
> > bad ones) versions of lint give interesting results.
>
> All versions of "lint" that I know of complain when you say something like
>
>       (int *)(char *)0;

My handy-dandy vanilla-flavored SysV lint blesses expressions like
these, for example:

    int *f(p) int *p; {
        return ( (int *)(char *)p );
    }

> since you're casting a pointer of one type to a pointer of another type
> which is, in general, dangerous.

But-but-but... "casting a pointer of one type to a pointer of another
type" is "in general, dangerous"?  You mean that constructs like

    foo_ptr = (foo_type *)malloc( sizeof( foo_type ) );

are "in general, dangerous"?    Say it ain't so!

I'm not quite sure what Guy was asserting above, but I suspect that it
all boils down to "casting expressions of pointer type to another
pointer type *can* be dangerous (or machine dependant) in *some* cases
(such as (int *)char_ptr)", which is indeed the case.  However, I'd
hesitate to say that such casts are dangerous *in general*.

As I understand things, pointer types can be cast safely when
    - the target type has a subset of the alignment requirements of the
      source type, or when
    - the source expression was created by a (machine dependant)
      magic routine such as malloc, or when
    - the source value was "originally" created by safely casting an
      expression of the target type to be the source type.
      (note the recursion in this subrule)

Normally, char * has a subset of the alignment requirements of all other
types (but note that nothing much can be said of the relative alignment
requirements of any pointer-type-pair not including char *).

So, when "should" pointer casting be done?  There is really only one
reason:  To store/fetch pointers in a "cannonical form", to implement
the notion of "pointer to any type at all".  This generic type should be
char *, unless there are machine dependant reasons why it should be
something else (and note that any such decision must take into account
the resulting decreased portability).  (And under ANSII C, the generic
type should be void *.)

In any event, the expression (foo_type *)(bar_type *)expr is only a
little more dangerous than (float)(int)expr.  In either case, there are
some machine dependancies lurking to zap the unwary.

>       Guy Harris
-- 
Wayne Throop at Data General, RTP, NC
<the-known-world>!mcnc!rti-sel!rtp47!throopw



More information about the Comp.lang.c mailing list