jimad@microsoft.UUCP (Jim ADCOCK) (02/28/90)
/******** Is the following program legal, illegal, or undefined? [It compiles and runs "correctly" under cfront 2.0] The program deals with the issue of the reference equivalent to a null pointer -- ie what one would get if one could dereference a null pointer and asssign the result to a reference. As the following shows, at least under cfront 2.0, the dereference followed by assignment to a reference is a conceptual dereference only --not actually done in machine code-- and thus causes no null-pointer fault. While the following example is weak, I claim assigning a "null" to a reference is useful when defining iterators returning references rather than pointers. [I don't believe this issue is covered in the C++ references] ********/ class OW { char ow[4]; public: OW(char* p) { strncpy(ow, p, 4); } void print() { printf("%s ", ow); } }; OW how("how"); OW now("now"); OW bow("bow"); OW wow("wow"); OW* pow[] = { &how, &now, &bow, &wow, 0 }; int main() { int i = 0; while (1) { OW& row = *pow[i++]; if (!&row) break; row.print(); } return 0; };
rfg@ics.uci.edu (Ronald Guilmette) (02/28/90)
In article <51083@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >/******** > >Is the following program legal, illegal, or undefined? > >[It compiles and runs "correctly" under cfront 2.0] Not surprizing at all. > >The program deals with the issue of the reference equivalent to a null >pointer -- ie what one would get if one could dereference a null pointer >and asssign the result to a reference. As the following shows, at least >under cfront 2.0, the dereference followed by assignment to a reference is >a conceptual dereference only --not actually done in machine code-- and >thus causes no null-pointer fault. While the following example is weak, >I claim assigning a "null" to a reference is useful when defining >iterators returning references rather than pointers. You have shown that it is useful, and you have done so quite clearly. Did anyone suggest that is wasn't useful? > >[I don't believe this issue is covered in the C++ references] Agreed, but then it doesn't have to be. In effect, on the fifth iteration you make `row' be a reference to a hypothetical `ow' object which happens to be located at address zero. You then check to see if the address of the refered to object is zero before you do anything rash to it. It's so simple that it is intutive. Why clutter up the manual? P.S. My rule of thumb is that references are exactly like const pointers only different (due to the implicit dereferencing). > >********/ > >class OW >{ > char ow[4]; >public: > OW(char* p) { strncpy(ow, p, 4); } > void print() { printf("%s ", ow); } >}; > >OW how("how"); OW now("now"); OW bow("bow"); OW wow("wow"); >OW* pow[] = { &how, &now, &bow, &wow, 0 }; > >int main() >{ > int i = 0; > while (1) > { > OW& row = *pow[i++]; > if (!&row) break; > row.print(); > } > return 0; >};
jimad@microsoft.UUCP (Jim ADCOCK) (03/08/90)
In article <25EB8EE8.8462@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes: >In article <51083@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >>Is the following program legal, illegal, or undefined? >>[It compiles and runs "correctly" under cfront 2.0] >Not surprizing at all. Always surprising 1/2 :-) >>The program deals with the issue of the reference equivalent to a null >>pointer -- ie what one would get if one could dereference a null pointer >>and asssign the result to a reference. As the following shows, at least >>under cfront 2.0, the dereference followed by assignment to a reference is >>a conceptual dereference only --not actually done in machine code-- and >>thus causes no null-pointer fault. While the following example is weak, >>I claim assigning a "null" to a reference is useful when defining >>iterators returning references rather than pointers. > >You have shown that it is useful, and you have done so quite clearly. Did >anyone suggest that is wasn't useful? No, but I suggest that it has not yet been defined as "legal", and in fact there are hints in the reference that this behaviour should presently be considered "undefined." If this behaviour is defined as "legal," then this is going to have impact on mapping C++ to systems with [hardware support for] typed pointers, such as "Rekursiv." >>[I don't believe this issue is covered in the C++ references] > >Agreed, but then it doesn't have to be. In effect, on the fifth iteration >you make `row' be a reference to a hypothetical `ow' object which happens >to be located at address zero. You then check to see if the address of the >refered to object is zero before you do anything rash to it. > >It's so simple that it is intutive. Why clutter up the manual? Simple, but wrong. Reading the reference, I find: "A constant expression that evaluates to 0 is converted to a pointer, commonly called the null pointer. It is guaranteed that this value will produce a pointer distinguishable from a pointer to any object." If the null pointer does not point to any object, then why should I assume that I can take the address of that "object" which isn't an object? What guarantee is there that an object that doesn't exist even has an address? And why should that address be "0" ??? It may be that many present systems represent *some* C++ null pointers as 32 bits all zero, but this is not the same as saying making such an assumption is portable to future systems. In particular, a system with [hardware support for] typed pointers would not have null pointers represented as 32 bits all zero. Also, note that the "0" that creates a null pointer must be a constant expression -- allowing a compiler to construct a special representation for null pointers at compile time. Also note: This means the fairly common "C" coding technique of assigning to a pointer a runtime expression that evaluates to zero is not guaranteed to be legal. And assigning one null pointer to a different type of pointer need not keep the same bit representations. >P.S. My rule of thumb is that references are exactly like const pointers >only different (due to the implicit dereferencing). Like many rules of thumb, this one is quite wrong. References are not even first class citizens. Like register variables, references don't even have an address. sizeof(aRefToOb) is the sizeof(Ob), whereas sizeof(aPtrToOb) is typically the native size of a pointer on your system [2 or 4, typical]. Further, using references may generate temporaries where using pointers does not. So, I interpret your response to be: "This is presently undefined, but who cares, its trivial." Well, I care, and I claim its not a trivial issue, but rather has important impact for the mapping of C++ onto systems with typed pointers. If making null references *is* legal, let someone in the know state so uneqivocally, and I can get on with my programming. I'd like to see this made explicetly legal -- but doing so may have a sharp negative impact on systems with typed pointers.
rfg@ics.uci.edu (Ronald Guilmette) (03/10/90)
In article <52081@microsoft.UUCP> jimad@microsoft.UUCP (Jim ADCOCK) writes: >... Reading the [ C++ ] reference, I find: > >"A constant expression that evaluates to 0 is converted to a pointer, >commonly called the null pointer. It is guaranteed that this value will >produce a pointer distinguishable from a pointer to any object." > >If the null pointer does not point to any object, then why should >I assume that I can take the address of that "object" which isn't an >object? What guarantee is there that an object that doesn't exist >even has an address? And why should that address be "0" ??? > >It may be that many present systems represent *some* C++ null pointers >as 32 bits all zero, but this is not the same as saying making such >an assumption is portable to future systems. In particular, a system >with [hardware support for] typed pointers would not have null pointers >represented as 32 bits all zero. > >Also, note that the "0" that creates a null pointer must be a constant >expression -- allowing a compiler to construct a special representation >for null pointers at compile time. Also note: This means the fairly >common "C" coding technique of assigning to a pointer a runtime expression >that evaluates to zero is not guaranteed to be legal. And assigning >one null pointer to a different type of pointer need not keep the same >bit representations. Jim, I see that I should not have been nearly so cavalier in response to your questions about "null references". You raise some important questions. Note however that many of these questions apply equally well to the C standard. For instance, in C, should the following be considered legal? void *vp; vp = 0; vp = &(*vp); Also, you noted the obscure restriction that a null pointer must be something created from "an integral constant expression with the value 0" (see ANSI C standard 3.2.2.3). This could be an issue for both C and C++, since it would seem to place in doubt the validity of the following: int nil () { return 0; } ... void *vp; vp = (void *) nil (); I am cross posting this to comp.std.c just to see if anyone there will clarify for us the legality (or illegality) of the two examples above (and possibly also the relevant rationale). >So, I interpret your response to be: "This is presently undefined, >but who cares, its trivial." Well, I care, and I claim its not >a trivial issue, but rather has important impact for the mapping of >C++ onto systems with typed pointers. If making null references >*is* legal, let someone in the know state so uneqivocally, and I >can get on with my programming. I'd like to see this made explicetly >legal -- but doing so may have a sharp negative impact on systems >with typed pointers. At the very least, these issues should be clarified a bit, both for C++ and for C. // Ron Guilmette (rfg@ics.uci.edu) // C++ Entomologist // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
henry@utzoo.uucp (Henry Spencer) (03/11/90)
In article <25F8D2FB.10981@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes: >...noted the obscure restriction that a null pointer must be >something created from "an integral constant expression with the value 0" >(see ANSI C standard 3.2.2.3). This could be an issue for both C and >C++, since it would seem to place in doubt the validity of the following: > > int nil () > { > return 0; > } > > ... > > void *vp; > > vp = (void *) nil (); This code is illegal in C, and always has been. There is no general relationship between the integer value 0 and the null pointer. An integer *constant* value equal to zero in a pointer context is automatically converted to a null pointer; this may be a non-trivial conversion, and is guaranteed valid only at compile time. The result of converting the integer value 0 to a pointer at run time is implementation-defined. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
henry@utzoo.uucp (Henry Spencer) (03/11/90)
In article <1990Mar11.015305.28264@utzoo.uucp> I wrote: >This code is illegal in C, and always has been... The result of converting the >integer value 0 to a pointer at run time is implementation-defined. Oops; change "illegal" to "naive, improper, unreliable, and unportable". It's thoroughly bad code, but it is not actually illegal, as my own further comments implied. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
haug@almira.uucp (Brian R Haug) (03/12/90)
In article <1990Mar11.015305.28264@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >In article <25F8D2FB.10981@paris.ics.uci.edu> rfg@ics.uci.edu (Ronald Guilmette) writes: >>...noted the obscure restriction that a null pointer must be >>something created from "an integral constant expression with the value 0" >>(see ANSI C standard 3.2.2.3). This could be an issue for both C and >>C++, since it would seem to place in doubt the validity of the following: >> >> int nil () >> { >> return 0; >> } >> >> ... >> >> void *vp; >> >> vp = (void *) nil (); > >This code is illegal in C, and always has been. There is no general >relationship between the integer value 0 and the null pointer. An >integer *constant* value equal to zero in a pointer context is automatically >converted to a null pointer; this may be a non-trivial conversion, and is >guaranteed valid only at compile time. The result of converting the >integer value 0 to a pointer at run time is implementation-defined. Henry, I beg to differ. I see where you are coming from with the wording: "an integral constant expression with the value 0", but in K&R First edition, page 97, there is an explicit example which 0 is returned by a function returning a pointer to a character. Also, from the text "C guarantees that no pointer that validly points at data will contain zero, so a return value of zero can be used to signal an abnormal event,..." Also, from Appendix A, section 7.7 (Equality operators) "A pointer may be compared to an integer, but the result is machine dependent unless the integer is the constant 0. A pointer to which 0 has been assigned is guaranteed no to point to any object, and will appear to be equal to 0; in conventional usage, such a pointer is considered to be null." This implies to me that I can compare a pointer to any arbitrary expression which evaluates to 0 and have machine independent behavior. And from section 7.14, "it is guaranteed that the assignment of the constant 0 to a pointer will produce a null pointer distinguishable from a pointer to any object." Since the "BNF" for this section lists "lvalue = expression," I would assume that if expression evaluates to 0 then the pointer will produce a null pointer distinguishable from a pointer to any object. As far as ANSI C goes, I do not have easy access to the standard at the current time, nor the experience reading it. However, I would have expected this behavior to be brought forward (hopefully not a silly idea, but we'll see). This was a quick scan through K&R, so I hope I have not taken anything out of context. The only reason this objection stuck in my mind is that I had once thought of doing an implementation where NULL != 0, but after further reading convinced myself the implementation would be invalid. Share and Enjoy! Brian Haug Disclaimer: These opinions are mine alone.
tim@nucleus.amd.com (Tim Olson) (03/12/90)
In article <1990Mar11.222634.2701@almira.uucp> haug@Columbia.NCR.COM (Brian Haug) writes: | In article <1990Mar11.015305.28264@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: | >This code is illegal in C, and always has been. There is no general | >relationship between the integer value 0 and the null pointer. An | >integer *constant* value equal to zero in a pointer context is automatically | >converted to a null pointer; this may be a non-trivial conversion, and is | >guaranteed valid only at compile time. The result of converting the | >integer value 0 to a pointer at run time is implementation-defined. | | Henry, | I beg to differ. I see where you are coming from with the wording: | "an integral constant expression with the value 0", but in K&R First edition, | page 97, there is an explicit example which 0 is returned by a function | returning a pointer to a character. That is a correct use. Just as in an assignment to a pointer type, the compiler knows that it is to coerce the integral constant 0 to the machine-specific nil representation for that pointer type. This differs from the case that was being discussed, in that the return value is specifically declared to be a pointer type. In the previous discussion, the return value was declared "int". | Also, from Appendix A, section 7.7 (Equality operators) "A pointer may be | compared to an integer, but the result is machine dependent unless the integer | is the constant 0. A pointer to which 0 has been assigned is guaranteed no to ^^^^^^^^^^ | point to any object, and will appear to be equal to 0; in conventional usage, | such a pointer is considered to be null." This implies to me that I can | compare a pointer to any arbitrary expression which evaluates to 0 and have | machine independent behavior. Not unless it is a constant expression that evaluates to 0. Constant expressions are a subset of expressions that involve only integral constants and certain operators -- function calls are not allowed. -- Tim Olson Advanced Micro Devices (tim@amd.com)
henry@utzoo.uucp (Henry Spencer) (03/13/90)
In article <1990Mar11.222634.2701@almira.uucp> haug@Columbia.NCR.COM (Brian Haug) writes: > I beg to differ. I see where you are coming from with the wording: >"an integral constant expression with the value 0", but in K&R First edition, >page 97, there is an explicit example which 0 is returned by a function >returning a pointer to a character... K&R1 was kind of sloppy about this, partly because the pdp11 let you get away with a lot. However, the definition of C was the reference manual, not the textbook... > Also, from Appendix A, section 7.7 (Equality operators) "A pointer may be >compared to an integer, but the result is machine dependent unless the integer >is the constant 0. A pointer to which 0 has been assigned is guaranteed no to >point to any object, and will appear to be equal to 0; in conventional usage, >such a pointer is considered to be null." This implies to me that I can >compare a pointer to any arbitrary expression which evaluates to 0 and have >machine independent behavior... How do you conclude this from a statement which explicitly says that the comparison is machine-dependent unless the *constant* 0 is used? >And from section 7.14, "it is guaranteed that >the assignment of the constant 0 to a pointer will produce a null pointer >distinguishable from a pointer to any object." Since the "BNF" for this >section lists "lvalue = expression," I would assume that if expression >evaluates to 0 then the pointer will produce a null pointer distinguishable >from a pointer to any object. Again, you're ignoring the fact that the text quite explicitly calls for the *constant* 0 to be used. The BNF defines only the syntax, not the semantics and type structure; it must be read together with the text to understand the language. > As far as ANSI C goes, I do not have easy access to the standard at the >current time, nor the experience reading it. However, I would have expected >this behavior to be brought forward... ANSI C carries forward the rules from K&R1 and later references: a null pointer is an integer *constant* zero converted to a pointer type. ANSI does permit a *constant* expression which evaluates to zero, e.g. "1-1", but that does not remove the requirement that the value be known at compile time. >... I had >once thought of doing an implementation where NULL != 0, but after further >reading convinced myself the implementation would be invalid. Not invalid, no; I think there are one or two such. Unwise, yes, because many many programs are sloppy about this and have to be fixed to run on such an implementation. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
gordon@sneaky.UUCP (Gordon Burditt) (03/13/90)
Implementations in which the value of a null pointer is not zero are legal, but painful. > I beg to differ. I see where you are coming from with the wording: >"an integral constant expression with the value 0", but in K&R First edition, >page 97, there is an explicit example which 0 is returned by a function The example shows the integer constant 0 being returned from a function that returns a pointer to character. Fine. The compiler can convert it to: movl #0xdeadbee1,d0 rts at compile time. The compiler knows it has to convert 0 in a return statement to the type of the return type of the function. >returning a pointer to a character. Also, from the text "C guarantees that no >pointer that validly points at data will contain zero, so a return value of >zero can be used to signal an abnormal event,..." "contain 0": that combination of bits that results from executing: p = 0; commonly implemented by: movl #0xdeadbee1,_p > Also, from Appendix A, section 7.7 (Equality operators) "A pointer may be >compared to an integer, but the result is machine dependent unless the integer >is the constant 0. A pointer to which 0 has been assigned is guaranteed no to ^^^^^^^^^^ >point to any object, and will appear to be equal to 0; in conventional usage, "appear to be equal to zero" means p == 0 is true, not something involving peeking at bits in a machine register. >such a pointer is considered to be null." This implies to me that I can >compare a pointer to any arbitrary expression which evaluates to 0 and have It sure doesn't imply that to me. The zero being discussed is constant 0, not an int variable containing 0. The comparison p == 0 (to yield a "boolean" value, not a branch) might be translated as: cmpl #0xdeadbee1,_p jeq .L5001 movl #0,d0 jmp .L5002 .L5001: movl #1,d0 .L5002: Slow, yes. But a perfectly legal implementation. >machine independent behavior. And from section 7.14, "it is guaranteed that >the assignment of the constant 0 to a pointer will produce a null pointer ^^^^^^^^^^ >distinguishable from a pointer to any object." Since the "BNF" for this >section lists "lvalue = expression," I would assume that if expression >evaluates to 0 then the pointer will produce a null pointer distinguishable >from a pointer to any object. Where do you get that assumption? It is legal to assign an integer expression to a pointer, but that doesn't make it machine-independent. The BNF certainly doesn't say anything explicitly about the machine-dependent characteristics of addition with overflow, division by zero, or shifts by negative amounts, so why should it be expected to say something in this case? Just before the section you quoted, it says, "The compilers currently allow a pointer to be assigned to an integer, an integer to a pointer, and a pointer to a pointer of another type. The assignment is a pure copy operation, with no conversion. This usage is unportable, and may produce pointers which cause addressing exceptions when used." Since "an integer variable containing zero" does not fit the exception for the integer constant zero, assigning one to a pointer IS unportable. > As far as ANSI C goes, I do not have easy access to the standard at the >current time, nor the experience reading it. However, I would have expected >this behavior to be brought forward (hopefully not a silly idea, but we'll >see). ANSI C seems quite careful NOT to require that the representation of a null pointer is all zero bits. > This was a quick scan through K&R, so I hope I have not taken anything >out of context. The only reason this objection stuck in my mind is that I had >once thought of doing an implementation where NULL != 0, but after further >reading convinced myself the implementation would be invalid. Don't confuse NULL and the bits used to represent a null pointer. NULL == 0 must be true. assembly_language_representation_of(NULL) == 0 need not be true. An implementation in which ((char *) NULL) == 0 and ((char *) NULL) == 0xdeadbee1 are both true is possible, provided that assembly-language address 0xdeadbee1 isn't a possible address for a variable. Gordon L. Burditt sneaky.lonestar.org!gordon
henry@utzoo.uucp (Henry Spencer) (03/14/90)
In article <1990Mar12.175613.12082@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >>... in K&R First edition, >>page 97, there is an explicit example which 0 is returned by a function >>returning a pointer to a character... > >K&R1 was kind of sloppy about this, partly because the pdp11 let you get >away with a lot... Oops, I goofed. (Yesterday was a bad day...) There is no problem with this. The function is known to return pointer to character, so the "return(0)" [actually "return(NULL)", prefaced by "#define NULL 0"] gets compiled as if it were "return((char *)0)" and everything is fine. By the time the value reaches the caller, it has already been converted to a pointer. Automatic conversion in "return" has been in the language since well before K&R1 (I can remember when it arrived, but that was a *long* time ago). On closer inspection of K&R1, at the prodding of a friend, no, K&R1 is *not* sloppy about this. I can't find any instance where the rules are being violated. Conversion of zero to pointer is always conversion of the constant 0. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
guy@auspex.auspex.com (Guy Harris) (03/14/90)
> I beg to differ. I see where you are coming from with the wording: >"an integral constant expression with the value 0", but in K&R First edition, >page 97, there is an explicit example which 0 is returned by a function >returning a pointer to a character. Since the compiler knows that the function is supposed to return a "char *", the compiler knows that the integral constant with the value 0 being returned by that function should be converted to a null pointer-to-char. In other words, said function doesn't return an integral value of 0, it returns a null pointer-to-char. This conversion is no different from the conversion in char *p; p = 0; or extern void foo(char *p); foo(0); or char *p; if (p == 0) ... or even char *p; if (!p) /* equivalent to previous example */ ... The same applies to: >Also, from the text "C guarantees that no >pointer that validly points at data will contain zero, so a return value of >zero can be used to signal an abnormal event,..." since if your function returns a pointer value, it had better be defined as doing so....
ken@argus.UUCP (Kenneth Ng) (03/14/90)
In article <1990Mar12.175613.12082@utzoo.uucp>, henry@utzoo.uucp (Henry Spencer) writes:
: ANSI C carries forward the rules from K&R1 and later references: a null
: pointer is an integer *constant* zero converted to a pointer type. ANSI
: does permit a *constant* expression which evaluates to zero, e.g. "1-1",
: but that does not remove the requirement that the value be known at
: compile time.
[edit]
: >once thought of doing an implementation where NULL != 0, but after further
: >reading convinced myself the implementation would be invalid.
: Not invalid, no; I think there are one or two such. Unwise, yes, because
: many many programs are sloppy about this and have to be fixed to run on
: such an implementation.
I'm confused, is a non zero NULL pointer valid or not? I'm not asking if
it will break 90% of the programs out there that use 0 instead of NULL.
On a 370 here I'd love to define NULL as -1 because it will cause an
immediate addressing exception if it is referenced. But, I was told that
NULL is defined as always being the value zero.
: MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology
: an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
--
Kenneth Ng: Post office: NJIT - CCCC, Newark New Jersey 07102
uucp !andromeda!galaxy!argus!ken *** NOT ken@bellcore.uucp ***
bitnet(prefered) ken@orion.bitnet or ken@orion.njit.edu
henry@utzoo.uucp (Henry Spencer) (03/15/90)
In article <1623@argus.UUCP> ken@argus.UUCP (Kenneth Ng) writes: >I'm confused, is a non zero NULL pointer valid or not? I'm not asking if >it will break 90% of the programs out there that use 0 instead of NULL. >On a 370 here I'd love to define NULL as -1 because it will cause an >immediate addressing exception if it is referenced. But, I was told that >NULL is defined as always being the value zero. NULL is just a convenient way of writing the constant 0, for all practical purposes. It is *not*, by itself, a null pointer, because there is no "generic null pointer" type. NULL has to be converted to a specific pointer type to become a null pointer. That (compile-time) conversion may well change the representation in some strange way. `NULL' must remain 0 (or a close equivalent), but `(foo *)NULL' can be a different story. There is absolutely nothing wrong with having a pointer representation in which the bit pattern for a null pointer is not all zeros... except that there are a lot of old, badly-written programs which will break. Thus my earlier comment that it is valid but unwise. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
guy@auspex.auspex.com (Guy Harris) (03/15/90)
>I'm confused, is a non zero NULL pointer valid or not? The confusion stems from confusion over the meaning of "non-zero". 4.1.5: ... The macros are NULL which expands to an implementation-defined null pointer constant; ... 3.2.2.3: ... An integral constant expression with the value 0, or such an expression cast to type "void *", is called a *null pointer constant*. So if some implementation defines NULL as something other than 0 or (void *)0 or (17 - 17) or ((void *)(17 - 17)) or..., the implementation is not a valid C implementation. *However*, this does *not* mean that the implementation must *represent* a null pointer of any type as a bit string of all zero bits. >I'm not asking if it will break 90% of the programs out there that >use 0 instead of NULL. Defining NULL as something other than the values listed (or implied...) and having that be the only null pointer constant will break all of the programs out there at use 0 instead of NULL. Thus, doing so would be invalid. Representing a null pointer constant as something other than a bit string of all zero bits will not break *any* valid ANSI C program. It will break some *in*valid programs, which is why Henry described it as "unwise" even though it's completely valid. >On a 370 here I'd love to define NULL as -1 because it will cause an >immediate addressing exception if it is referenced. But, I was told that >NULL is defined as always being the value zero. If by "define NULL as -1" you mean putting in something like #define NULL -1 that would, indeed, be invalid. If you mean changing your 3*0 C implementation such that null pointers are represented by 32 1 bits, *including making sure that the statements char *p; p = 0; assigns a value of 32 1 bits to "p"* (this is a bit that confuses a lot of people who think that the "p = 0;" is obliged to assign an all-zero-bits value to "p"), then it would be valid as long as you make sure this representation convention is followed consistently; you also have to make sure that non-C code that calls C code or is called by C code obeys this convention.
karl@haddock.ima.isc.com (Karl Heuer) (03/15/90)
In article <1990Mar14.164539.23685@utzoo.uucp> henry@utzoo.uucp (Henry Spencer) writes: >There is absolutely nothing wrong with having a pointer representation in >which the bit pattern for a null pointer is not all zeros... except that >there are a lot of old, badly-written programs which will break. Thus my >earlier comment that it is valid but unwise. Note that "p = 0", "p == 0", "!p", "char *f() { return 0; }" are *not* examples of such badly-written code; they may be bad style, but the compiler is required to generate correct code involving a true null pointer. The only "dangerous" context (other than hacking with unions and such) is when a null pointer constant is being passed as an argument to a function. (In C++ and ANSI C, any argument not covered by a prototype. In old C, any function argument at all.) In particular, neither of the two calls execl("/bin/sh", "sh", "-i", 0); execl("/bin/sh", "sh", "-i", NULL); is correct; it should be written as either of execl("/bin/sh", "sh", "-i", (char *)0); execl("/bin/sh", "sh", "-i", (char *)NULL); But this problem can occur even without strange null pointers: such sloppy code will already break on certain implementations where pointers and ints have different lengths. Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint Followups to comp.lang.c.
shopiro@alice.UUCP (Jonathan Shopiro) (03/16/90)
To me the interesting question in this null pointer business is whether there is any circumstance where it is legal to say *p where p is a null pointer. For example, it is definitely legal to write void f(int* p) { if (p == 0) ... } int* x = 0; f(x); It is not obvious (to me) if it is legal in C to write void g(int* p) { if (&(*p) == 0) ... } int* x = 0; g(x); But nobody would write that code anyway, so who cares. However, in C++ there is an analog that is very likely to be written. void h(int& r) { if (&r == 0) ... } int* x = 0; h(*x); It seems to me that g() and h() are two ways of writing the same thing. I think it would be nice if they were both legal. I think the fundamental issue here is when is a pointer dereferenced? (Since it is clearly illegal to dereference the null pointer). I don't se why writing *p alone, or &*p should dereference p. -- Jonathan Shopiro AT&T Bell Laboratories, Warren, NJ 07060-0908 research!shopiro (201) 580-4229
roberto@ssd.csd.harris.com (Roberto Shironoshita) (03/17/90)
In article <1623@argus.UUCP> ken@argus.UUCP (Kenneth Ng) writes: > I'm confused, is a non zero NULL pointer valid or not? I'm not asking if > it will break 90% of the programs out there that use 0 instead of NULL. > On a 370 here I'd love to define NULL as -1 because it will cause an > immediate addressing exception if it is referenced. But, I was told that > NULL is defined as always being the value zero. The Dec. 88 draft states that <stddef.h> defines the macro NULL, which expands to an implementation-defined null pointer constant (section 4.1.5). \begin{quote} An integral constant expression with the value 0, or such an expression cast to type void *, is called a _null pointer constant_. (...) \end{quote} So the implementation has two choices: #define NULL 0 or #define NULL (void *)0 (where '0' stands for an integral constant expression that evaluates to 0). Your compiler is free to use whatever address it pleases when translating code, so long as the program does not consider it a valid address. Note that dereferencing a NULL pointer causes undefined behavior. -- || Internet: shirono@ssd.csd.harris.com Roberto Shironoshita || Harris Corporation || ...!novavax-\ Computer Systems Division || UUCP: -!hcx1!shirono || ...!uunet---/ DISCLAIMER: The opinions expressed here are my own; they in no way reflect the opinion or policies of Harris Corporation.
throopw@sheol.UUCP (Wayne Throop) (03/18/90)
> From: guy@auspex.auspex.com (Guy Harris) >> I'm confused, is a non zero NULL pointer valid or not? > The confusion stems from confusion over the meaning of "non-zero". While what Guy says in explanation is certainly correct, I think that the confusion is over the meaning of "NULL pointer", not non-zero. That is, Guy explained things thoroughly, but the basis of the problem is the distinction between properties of a name of a thing and properties of the thing itself. In the phrase "NULL pointer" in C, there are TWO levels of naming going on, either one of which could have the property "zeroness". Or let me put it this way. In C, the name of the nil pointer is called "NULL". But that's only what the name is CALLED, you see. The NAME of the nil pointer is "0". The nil pointer itself can have any bit pattern it pleases. The above sequence of statements explains 1) why NULL should only be used as a pointer (this is a convention). It shouldn't be used to mean ascii NUL 2) why the only proper definition of the macro NULL is the string "0". (or, actually, any way to spell the constant zero in C) (though, granted, the advent of ANSI C means that the best definition of NULL is arguably the string "((void*)0)" and variants on this theme. Nevertheless "0" remains proper.) 3) in just what way C's nil pointer may have a non-zero bit pattern. It omits explanations of why one should never (in K&R1 C) pass NULL as an argument without a cast to a specific pointer type. It also omits explanation of the fact that there isn't really one nil pointer, or (necessarily) one nil pointer bit pattern. (This is due to the fact that all pointer values in C have specific types.) So, to conclude, "NULL", in C should never have a "non-zero" definition. Any particular nil pointer value (eg, one named ((void*)0)) can have any bit pattern the implementor of a C language system chooses. -- Wayne Throop <backbone>!mcnc!rti!sheol!throopw or sheol!throopw@rti.rti.org
henry@utzoo.uucp (Henry Spencer) (03/18/90)
In article <ROBERTO.90Mar16130444@ecx1.ssd.csd.harris.com> shirono@ssd.csd.harris.com writes: > An integral constant expression with the value 0, or such an > expression cast to type void *, is called a _null pointer > constant_. (...) Note, also, that the cast to `void *' is legal not because it somehow creates a generic null pointer -- there is no such thing in C -- but because there may not be an integer type of the same size as a pointer, and breakage of old programs is minimized if NULL is the same size as a pointer. (Even on machines where pointers are not all the same size, one can at least reduce the breakage somewhat this way.) -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
sdm@cs.brown.edu (Scott Meyers) (03/18/90)
In article <10582@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: > void h(int& r) > { > if (&r == 0) ... > } > > int* x = 0; > h(*x); >I think the fundamental issue here is when is a pointer dereferenced? >(Since it is clearly illegal to dereference the null pointer). I don't Two comments: 1. In h(), r is a reference to an object. By definition, no object can have an address that is equal to 0, so (&r == 0) should always fail. 2. In the call h(*x), we don't know precisely when *x is evaluated, but since r is initialized with that value, it must occur prior to executing any of the body of h(). If you let the evaluation semantics get any lazier, then you have to worry about this problem: int z = 1; // global variable int fse() { z = 0; } // function with side effects void foo(int y) { // function that doesn't use its argument if (z) doSomething(); else doSomethingElse(); } int x; foo( fse() ); When do you evaluate fse()? If you don't initialize y with its value at the beginning of foo(), then when? You've got to do it before z is evaluated... Scott sdm@cs.brown.edu
rfg@ics.uci.edu (Ronald Guilmette) (03/18/90)
In article <10582@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: > > >To me the interesting question in this null pointer business is >whether there is any circumstance where it is legal to say *p >where p is a null pointer. ... >I think the fundamental issue here is when is a pointer dereferenced? >(Since it is clearly illegal to dereference the null pointer). I don't >se why writing ... > > &*p > >should dereference p. I think this discussion is comming full circle. If you scan backwards over the (20-30) postings on this issue you'll note that I said almost exactly this same thing 20-30 messages ago. It was quickly pointed out to me that I was I was being naive (which I now freely admit that I was) because the question becomes confusing if p contains a NULL pointer value. Perhaps we should just take a vote and put the issue to bed. // Ron Guilmette (rfg@ics.uci.edu) // C++ Entomologist // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
shopiro@alice.UUCP (Jonathan Shopiro) (03/19/90)
In article <33188@brunix.UUCP>, sdm@cs.brown.edu (Scott Meyers) writes: > In article <10582@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: > > void h(int& r) > > { > > if (&r == 0) ... > > } > > > > int* x = 0; > > h(*x); > >I think the fundamental issue here is when is a pointer dereferenced? > >(Since it is clearly illegal to dereference the null pointer). I don't > > Two comments: > > 1. In h(), r is a reference to an object. By definition, no object > can have an address that is equal to 0, so (&r == 0) should always > fail. But the question is, must a reference actually refer to an object? Just as a pointer can point to an object or to no-object, a reference could refer to an object or to no-object. Then, if a reference referred to no-object, (&r == 0) would succeed. Note that this has nothing whatsoever to do with the representation of a null pointer. If the reference r refers to no-object, then &r is the null pointer (however it is represented). It does have something to do with the representation of a reference. The representation would have to be capable of storing a reference to no-object, as well as a reference to any object. Since references are generally represented as pointers, this shouldn't be a problem. > 2. In the call h(*x), we don't know precisely when *x is evaluated, > but since r is initialized with that value, it must occur prior to > executing any of the body of h(). The real question is not _when_ is *x evaluated, but __how_. I claim that *x is evaluated differently in int i = *x; // eval *x for rvalue than in int* p = &*x; // eval *x for lvalue and if x is the null pointer, the first is illegal and the second should be legal, since x is never dereferenced. The call h(*x) is analogous to the second example. -- Jonathan Shopiro AT&T Bell Laboratories, Warren, NJ 07060-0908 research!shopiro (201) 580-4229
sdm@cs.brown.edu (Scott Meyers) (03/19/90)
In article <10595@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: >In article <33188@brunix.UUCP>, sdm@cs.brown.edu (Scott Meyers) writes: >> In article <10582@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: >> > void h(int& r) >> > { >> > if (&r == 0) ... >> > } >> > >> > int* x = 0; >> > h(*x); >> >> Two comments: >> >> 1. In h(), r is a reference to an object. By definition, no object >> can have an address that is equal to 0, so (&r == 0) should always >> fail. >But the question is, must a reference actually refer to an object? Just as >a pointer can point to an object or to no-object, a reference could refer to >an object or to no-object. Then, if a reference referred to no-object, >(&r == 0) would succeed. Yes, a reference must actually refer to an object. (For the purposes of this discussion, variables of build-in types, e.g., int, are objects.) That's why references have to be initialized. Pointers are a different story entirely, because they don't have to be initialized. The only way to get a reference to no-object would be something like this: Object *ptr = 0; Object& ref = *ptr; But here again *ptr has to be evaluated to initialize ref. >> 2. In the call h(*x), we don't know precisely when *x is evaluated, >> but since r is initialized with that value, it must occur prior to >> executing any of the body of h(). >The real question is not _when_ is *x evaluated, but __how_. I claim that >*x is evaluated differently in > > int i = *x; // eval *x for rvalue > >than in > > int* p = &*x; // eval *x for lvalue > >and if x is the null pointer, the first is illegal and the second should >be legal, since x is never dereferenced. The call h(*x) is analogous >to the second example. I disagree; I think the question of "when is *x evaluated" is as real a question as there is. Perhaps what you really want is a new "operator&*" that has some kind of special semantics. After all, in the presence of a user-defined operator&, who says *x has to yield an lvalue in the expression &*x? Getting back to the original point of this discussion, I personally believe that it would be very convenient to have "null references," but I also believe that they don't exist and that making them exist would complicate a language that already has more than its share of complications. ("C++: The Programming Language Instructor's Full Employment Act.") Of course, I also tend to believe that references are an idea whose time should never have come. Maybe someone can enlighten me: what do references offer besides syntactic sugar? From my limited vantage point, they're just like pointers, but you can't new/delete them, you can't reassign them, and you can't compare them against 0. Don't get me wrong: I like sugar as much as anybody else, but syntactic sweetness has never been C++'s strong suit. In the case of references, I find that the confusion outweighs the convenience. Scott sdm@cs.brown.edu
sharam@munnari.oz.au (Sharam Hekmatpour) (03/19/90)
From article <33209@brunix.UUCP>, by sdm@cs.brown.edu (Scott Meyers): > [...] > Of course, I also > tend to believe that references are an idea whose time should never have > come. Maybe someone can enlighten me: what do references offer besides > syntactic sugar? Nothing. But the syntactic sugar offered by references is so important in that you can't eliminate them without losing much of the convenience of C++. I can name two things: [1] Efficient implementation of overloaded operators that involve large objects (eg, matrices) requires the operands to be references. Pointers simply won't work. [2] A call to a function that returns a reference is an lvalue. This syntactic sugar is very useful. > From my limited vantage point, they're just like > pointers, but you can't new/delete them, you can't reassign them, and you > can't compare them against 0. There are things that you can do using references but not pointers. See my previous posting for an example involving a 'delete' that zeros pointers. > Don't get me wrong: I like sugar as much as > anybody else, but syntactic sweetness has never been C++'s strong suit. In > the case of references, I find that the confusion outweighs the > convenience. I disagree. High level languages are all about syntactic sugaring; eliminate them and what you end up with is an assembler-like language. > Scott > sdm@cs.brown.edu Sharam Hekmatpour sharam@munnari.oz.au
rfg@ics.uci.edu (Ronald Guilmette) (03/19/90)
In article <3374@munnari.oz.au> sharam@munnari.oz.au writes: >From article <33209@brunix.UUCP>, by sdm@cs.brown.edu (Scott Meyers): >> Don't get me wrong: I like sugar as much as >> anybody else, but syntactic sweetness has never been C++'s strong suit. In >> the case of references, I find that the confusion outweighs the >> convenience. In the case of references, I agree, but I fear that it is far to late to get them removed from the language. >I disagree. High level languages are all about syntactic sugaring; >eliminate them and what you end up with is an assembler-like language. Yes, but add too much "sugar" and you get Ada. // Ron Guilmette (rfg@ics.uci.edu) // C++ Entomologist // Motto: If it sticks, force it. If it breaks, it needed replacing anyway.
bart@videovax.tv.tek.com (Bart Massey) (03/19/90)
In article <10595@alice.UUCP> shopiro@alice.UUCP (Jonathan Shopiro) writes: > [...] > The real question is not _when_ is *x evaluated, but __how_. I claim that > *x is evaluated differently in > > int i = *x; // eval *x for rvalue > > than in > > int* p = &*x; // eval *x for lvalue > > and if x is the null pointer, the first is illegal and the second should > be legal, since x is never dereferenced. The call h(*x) is analogous > to the second example. The problem is that this precludes stupid compilers from generating code which dereferences x as a side effect -- *x is an lvalue in C, but it is still a value. Some unsophisticated bottom-up tree-based code generator may construct an expression tree for &*x which looks something like addr-of | deref | x and then generate code like move x to r0 ; bottom of expression tree move *r0 to r1 ; next level up move x to r2 ; whoops! addr-of! search down the tree for the lvalue move r2 to p ; whew! that was close and then not peephole optimize, since -O wasn't specified, leaving a potentially dangerous dereference in. Note that I can't give an example of such a C compiler offhand :-). The only analogue which comes immediately to mind is the old Apple MDS Pascal compiler for the Lisa, which will do this with sizeof(x^^), but you're probably not interested in *Pascal* :-). Given the limited usefulness of the above construct, and given that I otherwise might have the choice between a fairly good code generator and no compiler at all, what I think I want is for writing *p to require p to point at an object. The ANSI C draft (3.3.3.2) seems to agree with me. Bart Massey ..tektronix!videovax.tv.tek.com!bart ..tektronix!reed.bitnet!bart
raeburn@athena.mit.edu (Ken Raeburn) (03/23/90)
In article <ROBERTO.90Mar16130444@ecx1.ssd.csd.harris.com>, roberto@ssd.csd.harris.com (Roberto Shironoshita) writes: [Dec '88 dpANS says:] > \begin{quote} > An integral constant expression with the value 0, or such an > expression cast to type void *, is called a _null pointer > constant_. (...) > \end{quote} > > So the implementation has two choices: > > #define NULL 0 > or > #define NULL (void *)0 A small point of the logic of these arguments is nagging at me. Does the standard say that values equivalent to (void *)0 in pointer contexts cannot be used for the definition of NULL? Just to be weird, let us consider a machine/compiler combination which has a integral type that has more bits than a pointer uses. Say the machine uses 24 bits for addressing, and a "long int" provides 32. Could not "(void *) 0xc0000000" be used for NULL? The compiler would have to understand that the top bits should be stripped out for comparisons, or the architecture could provide a pointer-compare instruction; would it need to provide anything else? Or is this simply disallowed because the standard is worded wrong? Or is there something fundamental about it I am missing that would make it fail miserably? It would probably be a strange architecture that would do things this way, but I expect there are some strange architectures out there, each with its own reasons. -- Ken
jc@atcmp.nl (Jan Christiaan van Winkel) (03/23/90)
From article <1990Mar23.072132.7307@athena.mit.edu>, by raeburn@athena.mit.edu (Ken Raeburn): > a integral type that has more bits than a pointer uses. Say the machine > uses 24 bits for addressing, and a "long int" provides 32. Could not > "(void *) 0xc0000000" be used for NULL? The compiler would have to > > It would probably be a strange architecture that would do things this way, > but I expect there are some strange architectures out there, each with its > own reasons. I believe the Apple Macintosh used to use the upper 8 bits of a pointer to store information like relocatable or something. Now they've made their system "32-bit clean" and pointers are the full 32 bits. Note that I do not want to imply that the Mac has a strange architecture, nor that it doesn't... :-) JC.
guy@auspex.auspex.com (Guy Harris) (03/24/90)
>Does the standard say that values equivalent to (void *)0 in pointer >contexts cannot be used for the definition of NULL? Even if it did, what would the point be in doing so? If the value truly is equivalent, why is it any better than 0 or "(void *)0"?
karl@haddock.ima.isc.com (Karl Heuer) (03/24/90)
In article <1990Mar23.072132.7307@athena.mit.edu> Ken Raeburn <Raeburn@MIT.EDU> writes: >Could not "(void *) 0xc0000000" be used for [the macro] NULL? Oh, I suppose you *could* (by the as-if rule)--but the compiler still has to generate the right answer for "0" and "(void *)0", so now you've got one more "magic string" to worry about%. If you're going to do that, you might as well have it expand into "__builtin_NULL", which also allows compile-time detection of improper NULL usage&. Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint ________ % Also, people who understand that "0" is *always* a valid definition for "NULL" will suspect that you don't know what you're doing. & E.g. wrongly using NULL instead of '\0', or passing an uncasted NULL as a function argument not covered by a prototype.
roger@procase.UUCP (Roger H. Scott) (03/29/90)
I think people who take the address of reference variables should find another language to program in (how about `C'?). ;->
cline@cheetah.ece.clarkson.edu (Marshall Cline) (04/05/90)
In article <PCG.90Apr2162557@odin.cs.aber.ac.uk> pcg@odin.cs.aber.ac.uk (Piercarlo Grandi) writes: >... I have an 'int *' pointer 'p' that I know >points to a member 'b' of a class 'X'. I want the pointer to the whole >class object. Will this be legal? Will this be safe? Will it have type >'X *'? > auto X *x = p - &X::b; // (X *) = (int *) - (int X::*) Subtracting two pointers doesn't give you a pointer. >Suppose this works, and we have now a pointer 'x' to an object of class >'X' as well. Will this be true? > > p == (x + &X::b) // (int *) == ((X *) + (int X::*)) Adding two pointers doesn't give you a pointer. I'm suspect you meant, in the first case, to cast both pointers to char* (to add/subtract bytes not structs/ints), then cast (char*)&X::b to an int, then subtract, then cast the difference back to X* (phew!). Similarly you could contort the second example with (too many) casts. :-) Marshall Cline -- =============================================================================== Marshall Cline/ECE Department/Clarkson University/Potsdam NY 13676/315-268-3868 cline@sun.soe.clarkson.edu, bitnet: BH0W@CLUTX, uunet!clutx.clarkson.edu!bh0w Career search in progress: ECE faculty. Research oriented. Will send vitae. ===============================================================================
cline@cheetah.ece.clarkson.edu (Marshall Cline) (04/05/90)
In article <CLINE.90Apr4142209@cheetah.ece.clarkson.edu> cline@cheetah.ece.clarkson.edu (Marshall Cline) writes: (in other words, I just wrote): > I'm suspect you meant, in the first case, to cast both pointers to > char* (to add/subtract bytes not structs/ints), then cast (char*)&X::b > to an int, then subtract, then cast the difference back to X* (phew!). But Andrew Koneig recently pointed out that casting a pointer-to-member to an int is undefined (it must be this way otherwise the first member of a struct could come out 0, which is reserved to mean "ptr to nowhere"). My algorithm (cast, cast, subtract, cast) is therefore incorrect. Apologies. Marshall Cline -- =============================================================================== Marshall Cline/ECE Department/Clarkson University/Potsdam NY 13676/315-268-3868 cline@sun.soe.clarkson.edu, bitnet: BH0W@CLUTX, uunet!clutx.clarkson.edu!bh0w Career search in progress: ECE faculty. Research oriented. Will send vitae. ===============================================================================
diamond@tkou02.enet.dec.com (diamond@tkovoa) (04/09/90)
In article <58@cdss.UUCP> culliton@cdss.UUCP (Tom Culliton) writes: >Another thought that stems from this and a little puzzle :-) how would you >implement sizeof as a macro? I don't think you can. How can a macro compute sizeof(-3) without using the builtin sizeof? (And in case you manage that, here are two more for you: sizeof -3 (no parentheses needed with an expression), and sizeof(int).) -- Norman Diamond, Nihon DEC diamond@tkou02.enet.dec.com This_blank_intentionally_left_underlined________________________________________
pcg@aber-cs.UUCP (Piercarlo Grandi) (04/13/90)
In article <CLINE.90Apr4142209@cheetah.ece.clarkson.edu> cline@sun.soe.clarkson.edu (Marshall Cline) writes: In article <PCG.90Apr2162557@odin.cs.aber.ac.uk> pcg@odin.cs.aber.ac.uk (Piercarlo Grandi) writes: >... I have an 'int *' pointer 'p' that I know >points to a member 'b' of a class 'X'. I want the pointer to the whole >class object. Will this be legal? Will this be safe? Will it have type >'X *'? > auto X *x = p - &X::b; // (X *) = (int *) - (int X::*) Subtracting two pointers doesn't give you a pointer. >Suppose this works, and we have now a pointer 'x' to an object of class >'X' as well. Will this be true? > > p == (x + &X::b) // (int *) == ((X *) + (int X::*)) Adding two pointers doesn't give you a pointer. My point here, and I post this in case somebody else missed it, was precisely that this does not work, even if member pointers have been described as if they were relative pointers, to the point (;->) that they are implemented as the offset of the member, plus one to avoid confusion between the zero'th offset and the binary pattern used to represent in many implementations the null (absolute) pointer. My article was a condemnation of existing member pointers precisely because they are only half baked relative pointers, and the above examples don't work, which they should if relative pointers were allowed. I also suggested some way to define the semantics of proper relative pointers as a C++ primitive, even if, given the ability to overload pointer dereferencing operator, and given either casts or templates, one can already define relative pointers (used by some as 'smart pointers' to define self relocating, sharable data areas). -- Piercarlo "Peter" Grandi | ARPA: pcg%cs.aber.ac.uk@nsfnet-relay.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcvax!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk