Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!auspex!guy From: guy@auspex.auspex.com (Guy Harris) Newsgroups: comp.lang.c Subject: Re: When is a cast not a cast? Message-ID: <1565@auspex.auspex.com> Date: 5 May 89 07:18:05 GMT References: <2747@buengc.BU.EDU> <10191@smoke.BRL.MIL> <2759@buengc.BU.EDU> <1556@auspex.auspex.com> <2764@buengc.BU.EDU> Reply-To: guy@auspex.auspex.com (Guy Harris) Organization: Auspex Systems, Santa Clara Lines: 102 > /* 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.