When is a cast not a cast?

Guy Harris guy at auspex.auspex.com
Fri May 5 17:18:05 AEST 1989


 >	/* How far apart are they? */
 >
 >	diffa = a2 - a1;  /* So far so C. */
 >
 >	/* The others should be aligned. */
 >
 >	b2 = b1 + diffa;  /* Did I just do that? */
 >
 >I've been doing things like that for years and thinking I was getting away
 >with the golden eggs.

I'm not sure what you're "getting away with".  You're setting things so
that the "difference" between "b2" and "b1" - i.e., the number of
elements between them - is the same as the "difference" between "a2" and
"a1".  If that's what you want to do, the above is a perfectly correct
and blessed way of doing it.

 >What I just did was add something that's _really_ a couple of bytes in
 >virtual size as though it was hundreds of bytes... if I think of them as
 >only indices, I'm fine.  It's when I start thinking in terms of physical
 >byte-slots, no matter how it's scaled, that my logical evaluator blows
 >a rectifier.

Well, my logical evaluator just blew on "really a couple of bytes in
virtual size as though it (were) hundreds of bytes"; I'm not sure what
you mean by that.  By "a couple of bytes in virtual size" do you really
mean "a couple of *elements*" (i.e., if the "struct" in question is 100
bytes long, and "diffa" is 2, then "b1" and "b2" are a couple of
*elements* away, but probably a couple of hundred *bytes* away)?

Another way of thinking of pointers is that a pointer to an array
element of type "t" is of a type that's a "superset" of the type
"pointer to type 't'", in some sense - it carries more baggage with it,
in that it not only indirectly represents the object to which it points
(as a pointer of type "pointer to type 't'" does) but it also represents
its position in the array to which the object to which it points
belongs.

In most C implementations, this information is implicit, in some sense,
in the address stored in that pointer - i.e., given the address of the
zeroth element of the array, and the type of the elements of the array
(and hence their size in storage units), and the address of the element
in question, you can compute the array index.

However, I could imagine a C implementation in which that information
was really carried around with the pointer - one that does bounds
checking on all array references, for example.  (I vaguely remember
something that led me to believe that a C implementation on a Symbolics
LISP machine did precisely that - is this true?  Does Saber C do
anything like that?)

@begin(Digression)

The pointer might contain three addresses - the address to which it
refers, the address of the first element of the array to which what it
points to belongs, and the address of the last element of that array (or
the address "one past" the address of that element).  (If the pointer
pointed to a scalar, it could be treated as pointing to the only member
of a one-element array.)

In such an implementation, "p + i" might be implemented as "add i*sizeof
(array element) to the address of the element to which 'p' pointers, and
then check whether the resulting pointer lies within the range specified
by the other two pointers, and barf if it isn't; leave the other two
pointers alone"; "p - q" might first check that the two "first element"
and "last element" pointers are the same, and barf if they aren't. 

"malloc" might return a pointer whose "current element" and "first
element" pointers are the same, and whose "last element" pointer has a
value that's the sum of the address of the first element and the number
of bytes allocated (the cast operation might check that the number of
bytes allocated is actually a multiple of the size of an array element).
"realloc" would return a pointer with the same "current element" and
"first element" pointers - after perhaps checking that they were the
same on input - and with a "last element" pointer updated according to
the new size.

@end(Digression)

 >It seems that I can actually put a segment, a board, or an ethernet link
 >in between elements array[33] and array[34], and I could still get that
 >
 >	a1 = array + 33;
 >	a2 = array + 34;
 >
 >	diffa = a2 - a1;
 >
 >and always expect diffa is exactly 1, even if the ethernet link separating
 >elements 33 and 34 of array[] is a million miles long.

You got it.  Pointer/integer addition, and pointer/pointer subtraction,
is *defined* to work that way.

 >I.e., scaling doesn't have to be constant.

"Scaling", in the sense of the commonly-imagined (and commonly present)
multiplication on pointer/integer addition and division on
pointer/pointer subtraction, is a characteristic of the implementation,
not a part of the language.  Most C implementations - possibly all
current ones - work "the way you expect them to", but that doesn't mean
it's part of the language.



More information about the Comp.lang.c mailing list