[comp.lang.c] pointer cast question

andrew@teletron.UUCP (Andrew Scott) (09/15/87)

I am curious as to why pointer casts behave the way they do.  Specifically,
casting from a pointer to one type to a pointer to another type may cause
address exceptions if the alignment requirements of the two types differ
(as described in section 14.4 of K&R).  Thus, it is the programmer's
responsibility to insure that the pointers involved in such expressions
point to valid addresses after the cast.

Why is this the case?  It seems to me that the cast should produce code
which aligns the pointer to a proper alignment boundary if necessary.  The
compiler should hide such a machine dependant thing from the programmer.
What is the purpose of such a cast (other than to make lint happy) if not
to convert a valid data value of one type to a valid data type of another?

Does anybody have any answers?

	Andrew

guy%gorodish@Sun.COM (Guy Harris) (09/20/87)

> Why is this the case?  It seems to me that the cast should produce code
> which aligns the pointer to a proper alignment boundary if necessary.

Except that this would mean that the pointer in question, after having been
"rounded up" or "rounded down" so to speak, would no longer point to the
location you thought it would point to.

> The compiler should hide such a machine dependant thing from the programmer.

So?  The compiler can't hide all the nasty details of the outside world from
programmers.  If you want to write machine-independent code, don't cast
pointers.  If you want to write machine-dependent code, go ahead, but take
responsibility for the consequences; be prepared for this code not to work on
machines other than the ones you wrote it for.

> What is the purpose of such a cast (other than to make lint happy) if not
> to convert a valid data value of one type to a valid data type of another?

OK, on a byte-addressible machine with 4-byte "int"s that disallows
off-boundary references to quantities longer than one byte (such as the machine
on which this message is being typed), how would you convert the value of a
"char *" containing the bit pattern "0xfeffffc1" into an "int *"?  Leave it
alone?  That would make it an invalid pointer.  Use the value of an "int *"
containing the bit pattern "0xfeffffc0" or "0xfeffffc4"?  That would mean you
wouldn't be pointing to "the 'int' at location 0xfeffffc1", i.e. the 4-byte
quantity with one end at location "0xfeffffc1" and the other end at location
"0xfeffffc5".

If the pointer in question is guaranteed not to be misaligned (e.g., pointers
returned by "malloc"), it would be wasteful to adjust the pointer.  If it is
not guaranteed to be misaligned, you have the two choices above, neither of
which gets you what you want.  As such, compilers generally take the "path of
least resistance" and make portable or reasonable-though-nonportable code work,
at the expense of making more *outr\'e* types of code not work.
	Guy Harris
	{ihnp4, decvax, seismo, decwrl, ...}!sun!guy
	guy@sun.com

gwyn@brl-smoke.ARPA (Doug Gwyn ) (09/21/87)

In article <100@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>...  Thus, it is the programmer's
>responsibility to insure that the pointers involved in such expressions
>point to valid addresses after the cast.
>Why is this the case?  It seems to me that the cast should produce code
>which aligns the pointer to a proper alignment boundary if necessary.

The compiler cannot tell how you intend to eventually use the converted
pointer.  It is exceeding unlikely that automatic rounding of a pointer's
address value (whatever that may mean) to some other alignment would
result in anything useful; if the pointer were not already properly
aligned (as malloc()'s return values are), then "adjusting" its value
would result in a new pointer that no longer pointed to sane data.

Generally, you should not attempt to play tricks with pointer casts
(other than on the result of malloc() and the argument to free())
until you're quite familiar with C.  If you declare types correctly,
such casts are seldom necessary, and they're almost always associated
with non-portable code.  (There are a few exceptions.)

andrew@teletron.UUCP (Andrew Scott) (09/21/87)

In article <6449@brl-smoke.ARPA>, gwyn@brl-smoke.ARPA (Doug Gwyn ) writes:
> 
> Generally, you should not attempt to play tricks with pointer casts
> (other than on the result of malloc() and the argument to free())
> until you're quite familiar with C.  If you declare types correctly,
> such casts are seldom necessary, and they're almost always associated
> with non-portable code.  (There are a few exceptions.)

Actually, this whole question came up because I am writing a form of
malloc() for a target operating system, obviously unportable.  I ended up
performing the necessary alignment myself, but I was just curious as to why
pointer casts exist if they basically do nothing.

On a (sort of) related question, one I am sure has been brought up before,
is there a way to make lint shut up about "possible pointer alignment"
problems when one is sure there are no problems (such as casting the return
value of malloc() )?   Our documentation does not mention any kind of
comment (like /* VARARGS */) which would do the trick.

	Andrew

franka@mmintl.UUCP (Frank Adams) (09/22/87)

In article <100@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>I am curious as to why ... casting from a pointer to one type to a pointer
>to another type may cause address exceptions if the alignment requirements
>of the two types differ (as described in section 14.4 of K&R).  ...  It
>seems to me that the cast should produce code which aligns the pointer to a
>proper alignment boundary if necessary. ...  What is the purpose of such a
>cast (other than to make lint happy) if not to convert a valid data value of
>one type to a valid data type of another?

The reason is speed.  Generally speaking, good programming practice (when it
produces such casts at all, which is not all that often) will always produce
a valid pointer in such cases.  The vast majority of such casts in good code
fall into one of two categories:

1) Casting the result of a malloc (or other allocation primitive) to the
type of the data being allocated.  In this case, proper alignment is
guaranteed by malloc, so fix up code is a waste of time.

2) A pointer is cast to a less restricted type (for example, "int *" to
"char *"), and then back again.  On the cast back, there can be no alignment
problem, since the value already was in the appropriate form.

Furthermore, what is the point of aligning the cast pointer to the proper
boundary?  This is almost always wrong, and it hides the error from the
programmer.  (Lots of machines will hide this error anyhow, but there is no
point in penalizing the programmers on better architectures.)
-- 

Frank Adams                           ihnp4!philabs!pwa-b!mmintl!franka
Ashton-Tate          52 Oakland Ave North         E. Hartford, CT 06108

gwyn@brl-smoke.ARPA (Doug Gwyn ) (09/25/87)

In article <101@teletron.UUCP> andrew@teletron.UUCP (Andrew Scott) writes:
>is there a way to make lint shut up about "possible pointer alignment"

No, not without modifying "lint".

throopw@xyzzy.UUCP (Wayne A. Throop) (09/28/87)

> andrew@teletron.UUCP (Andrew Scott)
> I was just curious as to why
> pointer casts exist if they basically do nothing.

IF pointer casts did basically did nothing, THEN their existance might
well be pointless.  But they *DO* do something.  They create a new value
which has the format of a pointer of the cast type.  On many machines,
where all pointers have the same format, this does nothing.  But the
conceptual operation is still important, because there are machines
where something must be done in such cases, such as casting from a short
pointer type to a long one in some PC C implementations, or from
character-granular pointer types to word-granular pointer types in some
word-oriented machines.

The cast operation doesn't guarantee the *alignment* of the result, but
it does guarantee the *format* if the alignment already makes sense.

--
Inigo hated it there.  Everybody was so dangerous, big, mean and
muscular, and so what if he was the greatest fencer in the world, who'd
know it to look at him?  He looked like a skinny Spanish guy it might be
fun to rob.  You couldn't walk around with a sign saying "Be careful,
this is the greatest fencer since the death of the Wizard of Corsica. Do
not burgle."
                        --- From The Princess Bride by William Goldman
-- 
Wayne Throop      <the-known-world>!mcnc!rti!xyzzy!throopw