Topic: Pointer comparisons
Author: jss@lucid.com (Jerry Schwarz)
Date: Wed, 23 Dec 92 18:24:56 GMT Raw View
Jim Adcock is advocating that under some circumstances it
is ok for a compiler to put two A objects at the same location.
His example is
|> class A {};
|>
|> class B : public A
|> {
|> public:
|> A a;
|> };
|>
B b ;
Where he claims it is ok for b.a and (B&)a to compare equal.
I don't agree, but I'm wondering exactly what criteria he is applying.
Does anything go for A's. E.g.
void f() {
A a1, a2 ; // can &a1==&a2
... ;
}
Is it only ok for "empty" classes? How about
struct D { int i; int j ; } ;
void f() {
D d1, d2 ;
... d1.i ... d2.j ... // never use d1.j or d2.i
}
Can &d1==&d2.
-- Jerry Schwarz
Author: jimad@microsoft.com (Jim Adcock)
Date: 24 Dec 92 01:12:54 GMT Raw View
In article <1992Dec18.181029.1061@taumet.com> steve@taumet.com (Steve Clamage) writes:
|Right. In the C Standard, it is stated explicitly that two pointers
|of the same type which compare equal point to the same object or
|function. There is no such statment for C++ in the ARM or in the
|current C++ Committee working draft.
What needs to be made clear includes what is meant by "point to the
same object." As in my example the pointers *do* point to the same object,
and they do compare equal. It's just that one pointer refers to an
enclosing object, and one pointer the enclosed object. Same object,
just not identically the same object.
Also needs to be clarified all the different implications. If two
pointers which compare equal point to the same object, do two pointers
to 'the same object' compare equal? Do two pointers not comparing
equal not point to the same object? Do two pointers not to the same
object not compare equal? These issues are much more obvious in C
than in C++.
Ultimately, I do not believe worrying about these pointer "details"
is very important unless one first decides what properties of object
identity C++ objects must have and why. The current permission of
C++ compilers to create temporaries at will kind of blows object identity
out of the water. Why worry about pointer equality, then?
One thing you might want to consider is dividing C++ objects into two categories
-- those with and without virtual functions or virtual bases. Then
just require "C" rules on those without virtualness. But require some
reasonable "object oriented" rules of object identity for those with
virtualness.
Alternately, just leave it implementation defined ;-)
Author: jimad@microsoft.com (Jim Adcock)
Date: 24 Dec 92 20:02:01 GMT Raw View
In article <1992Dec23.182456.17185@lucid.com> jss@lucid.com (Jerry Schwarz) writes:
|Jim Adcock is advocating that under some circumstances it
|is ok for a compiler to put two A objects at the same location.
NO I AM NOT SO ADVOCATING! I am saying it is legal for a compiler
to put objects wherever it so likes unless it doesn't explicitly
and clearly violate a requirement of the ARM.
Note that my example DOES NOT put two A objects at the same location.
Rather it puts an A object at the start of a B object such that the
A object has the same starting address as the B object. My claim is
that from "C" history this is nothing new. We EXPECT that the first
member of a structure has the same starting address as the structure.
We DO NOT EXPECT a compiler to gratuitously add padding at the
start of a structure. Any padding in a structure comes between
members of the structure, or at the end of a structure so that array
elements come out aligned.
|His example is
|
||> class A {};
||>
||> class B : public A
||> {
||> public:
||> A a;
||> };
||>
|
| B b ;
|
|Where he claims it is ok for b.a and (B&)a to compare equal.
I assume you make an accidental typo. On the contrary what I said it is
okay for &(b.a) and ((A*)&b) to compare equal. It is okay because ARM
says that unless the ARM states otherwise all pointer comparisons are
*implementation defined*
|I don't agree, but I'm wondering exactly what criteria he is applying.
The ARM. Show me a statement in the ARM that clearly contradicts this
behavior. If no statement clearly contradicts this possible implementation,
the implementation stands, because the ARM *explicitly* states that the
implementation stands unless called out otherwise.
|Does anything go for A's. E.g.
|
| void f() {
| A a1, a2 ; // can &a1==&a2
| ... ;
| }
Of course not! ARM clearly requires members within a labeled public/private/
protected section to be ordered with later members having "higher" addresses.
|Is it only ok for "empty" classes? How about
|
| struct D { int i; int j ; } ;
|
| void f() {
| D d1, d2 ;
| ... d1.i ... d2.j ... // never use d1.j or d2.i
| }
|
|Can &d1==&d2.
ARM:
"Two pointers to the same object compare equal. If two pointers
point to nonstatic members of the same object, the pointer to the later
declared member compares higher provided the two members not separated
by an *access-specifier* label ($r.11.1) and provided their class is not
a union. If two pointers point to nonstatic members of the same
object separated by an *access-specifier* label ($r.11.1) the result is
undefined. If two pointers point to data members of the same union,
they compare equal. If two pointers point to elements of the same
array or one beyond the end of the array, the pointer to the object
with the higher subscript compares higher. Other pointer comparisons
are implementation dependent."
Is your questioned pointer comparison listed here? No.
Therefore it is EXPLICITLY declared *implementation dependent* by the ARM.
Likewise with my first example that you questioned.
Author: jimad@microsoft.com (Jim Adcock)
Date: 24 Dec 92 20:08:40 GMT Raw View
In article <1992Dec22.140212.12579@bcrka451.bnr.ca> sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
|2. Perhaps there is a philosophical argument that might resolve this issue.
| If two objects have the same interface but no state (or constant state), and
| they have the same lifetime, are they in fact the same object? Or, perhaps,
| can they be treated as if they are the same object?
Here's a simple counterexample. b and b.a are clearly different objects.
They have different type, and they respond differently to a given method
call.
HOWEVER, they can both be legally used to initialized an A*, and
in which case the pointers compare equal, and the two different objects
THEN respond the same to a given method.
#include <iostream.h>
class A
{
public:
static void print() { cout << "A\n"; }
};
class B : public A
{
public:
A a;
static void print() { cout << "B\n"; }
};
main()
{
B b;
b.print();
b.a.print();
A* pb = &b;
A* pa = &(b.a);
if (pa == pb)
cout << "addresses match\n";
else
cout << "addresses don't match\n";
pb->print();
pa->print();
return 0;
}
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Fri, 25 Dec 1992 14:14:30 GMT Raw View
larsn@Autodesk.COM (Lars Nyman) writes:
[...]
>Thus, I cannot even trust that a '!=' test will return 1 for two objects
>that are not the same !
That is the only possible interpretation of the ARM (as it currently
stands).
>This must surely be wrong... can somebody, please, correct me and explain
>what I'm overlooking.
The definition of objects being "the same" is not clear.
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Fri, 25 Dec 1992 15:16:59 GMT Raw View
pkt@lpi.liant.com (Scott Turner) writes:
>In article <1992Dec19.001851.22116@microsoft.com>, jimad@microsoft.com (Jim Adcock) writes:
>> On the contrary, for the test to not prove true would
>> mean that the empty base class part has to be implemented by the compiler
>> using gratuitous padding, and gratuitous padding is an anathema to
>> traditional C/C++ implementation.
>
>"Gratuitous" is your own judgment. Some of us disagree.
>Moreover, such padding is in the C++ tradition.
One of the most important principles of C was that if you didn't use a
feature, you shouldn't have to pay for it. This principle was carried
through to C++. On the topic "Design Notes", Bjarne Stroustrup wrote
"Features that would incur run-time or memory overheads even when
not use were avoided" [C++PL, 2nd Ed. pg 3].
As a feature, padding empty base classes fits this description exactly.
It has a very significant memory overhead, especially if there
are multiple levels of derivation involved. Such padding could easily
double (or worse!) the memory required for classes derived from
abstract base classes.
Stroustrup goes on to say
"For example, ideas that would make it necessary to
store ``housekeeping information'' in every object
were rejected; if a user declares a structure consisting
of two 16-bit quantities, that structure will fit into
a 32-bit register" [Ibid.]
In the case of deriving from empty structures, it is absolutely TRIVIAL
to insert padding yourself *IF* you really need the addresses to be different.
If such padding were to be inserted by the compiler, then there would be
NO WAY to turn this feature off in cases where you weren't using it.
To force implementations to insert such padding would go against one of
the strongest guiding design principles for both C and C++.
As a final point, I believe that requiring padding when deriving from
abstract base classes would strongly discourage their use, for efficiency
reasons. This would be a very bad thing IMHO, because abstract base classes
are a very important design tool, and if the design can't be represented
directly in the programming language, then there is a significant cost
in terms of productivity and maintainability.
The concise OED defines "gratuitous" as (amoung other things)
"uncalled for, unwarranted". Given the above arguments, I would
definitely describe inserting padding when deriving from empty
classes as "unwarranted". Furthermore, if the programmer didn't
ask for the padding and didn't want it, how could you say it was
anything other than "uncalled for"?
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Fri, 25 Dec 1992 15:38:05 GMT Raw View
sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
>2. Perhaps there is a philosophical argument that might resolve this issue.
Philosophical arguments never resolve anything ;-)
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: pkt@lpi.liant.com (Scott Turner)
Date: Mon, 28 Dec 1992 15:11:46 GMT Raw View
In article <1992Dec24.011254.1982@microsoft.com>, jimad@microsoft.com (Jim Adcock) writes:
> What needs to be made clear includes what is meant by "point to the
> same object." As in my example the pointers *do* point to the same object,
> and they do compare equal. It's just that one pointer refers to an
> enclosing object, and one pointer the enclosed object. Same object,
> just not identically the same object.
This explanation of your example could be more clear.
If one pointer refers to an an enclosing object, and another to an enclosed
object, that sounds like different objects to me.
I've been advocating a strong relationship between pointer comparison
and identity of the objects pointed to. It occurs to me that pointers
of type void* do not fit into this framework in C++, and not really in
C either. If we want a guarantee that
(void*)&a == (void*)&a
then how would the standard specify it?
> Ultimately, I do not believe worrying about these pointer "details"
> is very important unless one first decides what properties of object
> identity C++ objects must have and why. The current permission of
> C++ compilers to create temporaries at will kind of blows object identity
> out of the water. Why worry about pointer equality, then?
I'd be happy to have a more precise description of C++ objects and their
identity, but temporaries are not much of a problem.
Programs rely on object identity via pointers, references, and lvalues.
12.2 of the ARM and working paper sanctions the introduction of temporaries,
but no one interprets this as affecting pointer, reference, and lvalue
expressions.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA (508) 872-8700
UUCP: uunet!lpi!pkt Internet: pkt@lpi.liant.com
Author: jimad@microsoft.com (Jim Adcock)
Date: 28 Dec 92 17:52:18 GMT Raw View
In article <1992Dec24.200201.25709@microsoft.com> jimad@microsoft.com (Jim Adcock) writes:
||Does anything go for A's. E.g.
||
|| void f() {
|| A a1, a2 ; // can &a1==&a2
|| ... ;
|| }
|
|Of course not! ARM clearly requires members within a labeled public/private/
|protected section to be ordered with later members having "higher" addresses.
Sorry -- to much eggnog -- I misread the question.
Let me restate the question as an answer.
Does the ARM anywhere say that two pointers of the same type to two different
objects of the same type not in the same array must compare not equal?
If not then what does the ARM say of any such comparison?
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Mon, 28 Dec 1992 04:37:19 GMT Raw View
In article <1992Dec22.174327.8903@lpi.liant.com> pkt@lpi.liant.com (Scott Turner) writes:
>Moreover, such padding is in the C++ tradition. The ARM requires padding
>in two places, where the principal intent is to support
>
> p and q point to different objects implies p!=q
>
> 1. 5.3.2 "The size of any class object is larger than zero."
>
> 2. 5.3.3 "This implies that an operator new() can be called with an
> argument zero. In this case, a pointer to an object is returned.
> Repeated such calls return pointers to different objects."
> [An example follows to demonstrate that the intent is that
> distinguishable pointers values be returned.]
IF this intent is to be fully supported, additional words would be
required to ensure base subobjects and included member objects
were also padded?
IF these words are not added, then the intent is not supported
fully, and the clauses above might as well be dropped?
I.E. I am asking if there is any point retaining the status
quo, or any other position where full pointer identity
is not supported yet padding is required.
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: jss@lucid.com (Jerry Schwarz)
Date: Tue, 29 Dec 92 04:28:28 GMT Raw View
jss:
|> ||Does anything go for A's. E.g.
|> ||
|> || void f() {
|> || A a1, a2 ; // can &a1==&a2
|> || ... ;
|> || }
|> |
jimad:
|> Let me restate the question as an answer.
|>
|> Does the ARM anywhere say that two pointers of the same type to two different
|> objects of the same type not in the same array must compare not equal?
|>
|> If not then what does the ARM say of any such comparison?
As far as I can tell, except for the special cases enumerated in
5.9 and some hints about the behavior of new, the ARM
never requires two pointers to compare unequal. I believe this is
an oversight and should be corrected in the standard when it emerges.
I believe the intention has always been that distinct objects have
distinct addresses and I belive that the final standard should say so.
What should x3j16/wg21 do? One alternative would be to leave
the words unchanged. (I think this is Jim's position,
but I'm not sure.) This apparently allows &a1==&a2 in the above,
and in other cases as well. If the committee does this, it
should do it explicitly after due consideration and not simply
allow the status quo to remain by default.
Another possibility which has been proposed here recently (sorry
I don't remember by whom) is to add something like "two pointers to
T (where T is an object type) compare equal if and only if they point
to the same object". This seems a useful rule to me. Note that
it makes no distinctions between "empty" and "non-empty" classes.
An alternative might be to apply this rule except for "empty"
classes.
So there really several related questions about this example.
A: Does the ARM currently require a1!=a2? Apparently
not, but I may have overlooked something.
B: What do existing compilers do. How common is the
code that might be affected if the compiler was
changed to do something else. How much existing
code currently assumes that a1!=a2.
D: Should the standard when it emerges require a1!=a2.
I think yes, and am concerned with exactly how to
word this requirement. There are many potential
examples and I would greatly prefer a general rule
to an enumeration of cases.
Knowing the answers to A and B for this and similar cases
might influence my opinion on C, but I am not prepared in advance
to state a rule that would allow you to derive my opinion of C
from the answers to A and B.
-- Jerry Schwarz
Author: eker@loria.fr (Steven Eker)
Date: 29 Dec 92 15:38:04 GMT Raw View
In article <1992Dec29.042828.27808@lucid.com>, jss@lucid.com (Jerry Schwarz) writes:
[stuff deleted]
|>
|> So there really several related questions about this example.
|>
|> A: Does the ARM currently require a1!=a2? Apparently
|> not, but I may have overlooked something.
|>
Has anyone noticed that slist_base::get() on p266 C++PL (2ed) assumes that
pointers to different heap allocated objects compare unequal?
Might this fail on a 486?
There doesn't seem to be an easy fix for this example without maintaining
a separate tail pointer.
Steven
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Tue, 29 Dec 1992 19:13:45 GMT Raw View
eker@loria.fr (Steven Eker) writes:
>jss@lucid.com (Jerry Schwarz) writes:
>|>
>|> A: Does the ARM currently require a1!=a2? Apparently
>|> not, but I may have overlooked something.
>
>Has anyone noticed that slist_base::get() on p266 C++PL (2ed) assumes that
>pointers to different heap allocated objects compare unequal?
I hadn't noticed that one, but on page 238 in string::operator=() it
assumes that pointers to different strings compare unequal, whether
heap allocated, stack allocated, or statically allocated.
>Might this fail on a 486?
Yes, but only if the programmer had invoked some operating system memory
mapping function, in which case the consequences are on that programmer's
head. It is not a matter for the standard to worry about.
>There doesn't seem to be an easy fix for this example without maintaining
>a separate tail pointer.
Hopefully we can all agree that there is plenty of code around like these
two examples, which we don't want to break. Whatever wording is adpoted
by the standard, these examples should continue to work unmodified.
Note carefully, however, that these examples do *not* depend on pointers
to different *empty* objects comparing unequal.
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: jimad@microsoft.com (Jim Adcock)
Date: 30 Dec 92 18:30:53 GMT Raw View
In article <9236101.2804@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON) writes:
>The definition of objects being "the same" is not clear.
Exactly. Also, the definition of "same type" and "pointer" is not
clear....
Author: steve@taumet.com (Steve Clamage)
Date: Fri, 18 Dec 1992 18:10:29 GMT Raw View
sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
>In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
>>
>> Two pointers to the same object compare equal. If two pointers
>...but nowhere do I see a statement that (p == q) ==> p and q point
>to the same object, even if p and q are the same type.
Right. In the C Standard, it is stated explicitly that two pointers
of the same type which compare equal point to the same object or
function. There is no such statment for C++ in the ARM or in the
current C++ Committee working draft.
I believe this issue needs to be resolved. (Obviously, we need
to exclude pointer-to-member from such a requirement.)
--
Steve Clamage, TauMetric Corp, steve@taumet.com
Author: larsn@Autodesk.COM (Lars Nyman)
Date: 18 Dec 92 22:09:23 GMT Raw View
ARM specifies what a comparison of two pointers to objects should return
IF:
- the objects are the same
- the objects are non-static members of same object
- the objects are elements of the same array
Otherwise, the pointer comparison is implementation dependent.
So, if I have pointers to two different objects the result of comparing
them is implementation defined !?!
Thus, I cannot even trust that a '!=' test will return 1 for two objects
that are not the same !
This must surely be wrong... can somebody, please, correct me and explain
what I'm overlooking.
Author: maxtal@extro.ucc.su.OZ.AU (John MAX Skaller)
Date: Fri, 18 Dec 1992 20:25:39 GMT Raw View
In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
>(I hope nobody minds my changing the subject line to something
>a little more succinct.)
>
>While responding to a previous posting, I looked up what the
>draft C++ standard (the September 17 version) had to say about
>pointer comparisons. Here's an extract from section 5.9:
>
> Pointers to objects or functions of the same type (after pointer
> conversions) may be compared; the result depends on the relative
> positions of the pointed-to objects or functions in the address
> space.
>
> Two pointers to the same object compare equal. If two pointers
> point to nonstatic data members of the same object, the pointer
> to the later declared member compares higher provided the two
> members [are] not separated by an access-specifier label (11.1)
> and provided their class is not a union. If two pointers
> point to nonstatic members of the same object separated by an
> access-specifier label (11.1) the result is unspecified.
> If two pointers point to data members of the same union, they
> compare equal (after conversion to void*, if necessary).
> If two pointers point to elements of the same array or one beyond
> the end of the array, the pointer to the object with the higher
> subscript compares higher. Other pointer comparisons are
> implementation dependent.
>
>Unfortunately, my copy of the C standard isn't at all handy, so
>I can't compare with what it says.
>
>Some of this is quite unclear to me.
>
>
>"Pointers ... may be compared". Does this mean any pair of pointers
>may be compared, or some pairs may be compared? It certainly suggests
>"any pair" to me, but some might interpret it as "some pairs".
>
Seems to many 'any' to me.
>
>"the result depends on the relative positions ... in the address
>space." What does this mean?
This means that the committee has committed a grave error.
Too many Unix people. The ARM also commits this error in
assuming the existence of *an* address space. The 386 has
8K address spaces per process. The idea that relative positioning
of pointers into different segments is meaningful is absurd.
>Must one convert the pointers into
>actual addresses and return the result of comparing those addresses?
>Probably not, given that "[o]ther pointer comparisons are
>implementation dependent." Maybe one is to convert the pointers
>into addresses and apply some (arbitrary) function to those addresses?
>If so, why would one want such a condition? What happens if there's
>more than one address space? This clause seems reasonable to me if
>interpreted as "the general intent of pointer comparison is to compare
>addresses", but perhaps it's not suitable as part of the specification
>of the language.
>
Agreed.
>
>"If two pointers point to elements of the same array ...".
>What if they point to members of elements?
>
> struct X { int a; int b; };
> X x[2];
>
>Must it be true that &x[0].a < &x[1].a? What about &x[0].b < &x[1].a?
>
I would expect this, but it doesnt say so.
>
>Let me try to be constructive for a change. Would something
>similar to the following be reasonable? (It would clearly need
>much more careful wording and attention to details.)
>
>1) Any two pointers to the same type may be compared, with any of
> the relational operators.
Sure, why not?
>
>2) In general, the results of the comparisons need not have anything
> to do with the objects to which the pointers point. For example,
> it is possible that p and q point to the same object, but p != q.
> (But see below.)
Yes. It is implementation defined, except in special
circumstances.
>
>3) The relational operators define a total ordering on the set of
> pointers of each type. (All the normal rules, including
> transitivity.)
Accepted as axiom tentatively.
>
>4) If two pointers p and q (of the same type) are obtained through
> sequences of "normal" operations, then
>
> p == q <==> p and q point to the same object
>
> If p and q point to elements of the same array, or to
> subobjects of _different_ elements of the same array,
> then they compare the same way as the indexes of the
> elements in the array.
Given we defer analysis of "normal" operations this
axiom may contradict axiom 4.
On a linear address machine, 3 & 4 could be made to work,
so such a system can exist. On a segmented machine, 3 & 4 might
be mutually exclusive.
>
>For rule (4), "normal" operations would include things such as
>the built-in & operator, adding integers to pointers to array
>elements, normal casts (eg. derived class pointer to base class
>pointer),
Dont forget the obvious ones: assignment and initialisation.
Also, some casts might be dubious, espcially casts to/from
void*.
>and calls to standard library functions.
I have some doubts about this.
>It would
>specifically exclude casts whose meaning is not defined by the
>standard (eg. casting an integer to a pointer) and calling an
>extern "C" function.
I think you would have to make ALL calls, even to
C++ functions problematic. Because a called extern C++ function
might do one of the excluded naughty casts.
This doesnt matter though.
>On systems where a pointer is composed of a segment identifier
>and an offset, the compiler might arrange that the "normal"
>operations would never change the segment identifier.
This is more complicated than you think.
The 386 'selector' is bits which contain selector access
priviledges, as well as the bits relating to the
actual entry in the descriptor table.
Furthermore, some system might mix 16 and 32 bit
segments (in fact all protected mode operating systems I
know about allow this) and often have some way of
'interconverting' between them.
Thus this requirement may be unimplementable.
>Comparisons could then be done by just comparing the
>segment identifier and offset. If two pointers to the same object
>have different segment identifiers, then the programmer must have
>applied some un"normal" operation, so it's OK if the pointers
>compare unequal.
This may or may not be true on the 386 or other machines.
I suspect suitable restrictions on 'normal' might make
this workable.
>
>One might add a library function sameObject(p,q) which would
>indicate whether p and q point to the same object, no matter
>how p and q were obtained.
>
One might, but it had better not be required.
Because it may be unimplementable on some systems.
>
>If we ignore the question of how much existing code this would
>break, is this a reasonable suggestion?
It is reasonable to start from this suggestion,
but you have to look at the fact that axiom 3 and axiom 4
might not be compatible.
>
>And how much existing code would this break (that isn't already
>broken)? Note that it doesn't break any code that restricts
>itself to "normal" operations.
>
You dont know that. How do you know that pointers
stored in one segment and those in another, BOTH pointing
to the same object dont have different layouts?
--
;----------------------------------------------------------------------
JOHN (MAX) SKALLER, maxtal@extro.ucc.su.oz.au
Maxtal Pty Ltd, 6 MacKay St ASHFIELD, NSW 2131, AUSTRALIA
;--------------- SCIENTIFIC AND ENGINEERING SOFTWARE ------------------
Author: pat@frumious.uucp (Patrick Smith)
Date: Fri, 18 Dec 1992 06:50:32 GMT Raw View
sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
|In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
|>
|> Two pointers to the same object compare equal. If two pointers
|
|...but nowhere do I see a statement that (p == q) ==> p and q point
|to the same object, even if p and q are the same type.
Nor do I. But I think I once saw a discussion of this, and someone
said this would be changed in a future version of the draft.
(My memory of this is vague, though, so I may be imagining things.)
|Is it possible for two objects of the same type to be in different
|segments and compare equal?
I would hope not, if they are different objects. But the draft
seems to allow it.
|>Would something
|>similar to the following be reasonable? (It would clearly need
|>much more careful wording and attention to details.)
|>
|>2) In general, the results of the comparisons need not have anything
|> to do with the objects to which the pointers point. For example,
|> it is possible that p and q point to the same object, but p != q.
|> (But see below.)
|
|Note that this provides your counterexample for
|
| (p == q) <==> (ptrcmp(p,q) == 0)
Yes, although this is under my proposal, not under the existing draft.
|>3) The relational operators define a total ordering on the set of
|> pointers of each type. (All the normal rules, including
|> transitivity.)
|
|Is this possible? Mightn't some objects of one type be in one segment
|and some in another? (Perhaps I should say "practical", not "possible").
I think it's possible, by doing bitwise comparisons of the pointers
(ignoring padding, if any). Remember that so far, the comparisons
don't have to be related in any way to the objects pointed to;
I am _not_ asking for a total order on the address space.
|>4) If two pointers p and q (of the same type) are obtained through
|> sequences of "normal" operations, then
|>
|> p == q <==> p and q point to the same object
|
|I could not find this statement in the current wording. Is there a
|reason why the current wording is weaker than this?
I don't know. The C standard requires both directions of the
implication. I'm not sure if the concept "p and q point to
the same object" is clearly defined anywhere.
|What do you mean by "normal" operations?
|What are examples of "abnormal" operations?
These were described lower down in my previous posting.
"Normal" operations are the ones whose semantics are defined
by the standard; "abnormal" ones are the others.
|>One might add a library function sameObject(p,q) which would
|>indicate whether p and q point to the same object, no matter
|>how p and q were obtained.
|
|Is this necessary if we have ptrcmp? If we like the name ptrcmp, shouldn't
|we like the name ptreq?
My idea with the above description of the operators was that ptrcmp
would be unnecessary; the operators could be used instead.
|Also, if p = (Base *)q, should sameObject(p,q) be 1?
Yes. And also p == q should be 1. But note that before doing
either comparison, q is converted to a Base* so that one has
two pointers of the same type.
--
Patrick Smith
uunet.ca!frumious!pat
pat%frumious.uucp@uunet.ca
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Mon, 21 Dec 1992 12:39:25 GMT Raw View
pat@frumious.uucp (Patrick Smith) writes:
>"Pointers ... may be compared". Does this mean any pair of pointers
>may be compared, or some pairs may be compared? It certainly suggests
>"any pair" to me, but some might interpret it as "some pairs".
I would interpret it to mean that any pair of pointers may be compared.
>"the result depends on the relative positions ... in the address
>space." What does this mean?
I think that this is intended to convey a general idea of the intent of the
standard-writers. I don't think it has any direct implications with
regard to the behaviour of an implementation. Perhaps it would be
more suitable as part of the commentary rather than as part of the
standard itself.
>"If two pointers point to elements of the same array ...".
>What if they point to members of elements?
>
> struct X { int a; int b; };
> X x[2];
>
>Must it be true that &x[0].a < &x[1].a? What about &x[0].b < &x[1].a?
Not according to the ARM as it stands. There might be a reasonable
case for extending the guarantee to these additional cases.
>Let me try to be constructive for a change. Would something
>similar to the following be reasonable? (It would clearly need
>much more careful wording and attention to details.)
>
>1) Any two pointers to the same type may be compared, with any of
> the relational operators.
>
>2) In general, the results of the comparisons need not have anything
> to do with the objects to which the pointers point. For example,
> it is possible that p and q point to the same object, but p != q.
> (But see below.)
I don't think that this is reasonable. It is necessary to be able to
detect when two pointers point to the same object in order to
write correct and efficient assignment operators in many cases.
>3) The relational operators define a total ordering on the set of
> pointers of each type. (All the normal rules, including
> transitivity.)
>
>4) If two pointers p and q (of the same type) are obtained through
> sequences of "normal" operations, then
>
> p == q <==> p and q point to the same object
>
> [list of other reasonable properties of pointer comparisons]
>
>For rule (4), "normal" operations would include things such as
>the built-in & operator, adding integers to pointers to array
>elements, normal casts (eg. derived class pointer to base class
>pointer), and calls to standard library functions. It would
>specifically exclude casts whose meaning is not defined by the
>standard (eg. casting an integer to a pointer) and calling an
>extern "C" function. (Actually, one could develop a notion of a
>C function which only does "normal" operations and permit
>calling such a function. (Is there already a concept of strictly
>conforming C function, as opposed to program?))
There is no need for these new notions of "normal" operations or
"strictly conforming functions". The "normal" operations should
just be all operations whose results are defined by the standard.
(See my earlier responses to John Skaller's posts.)
>On systems where a pointer can be treated as an integer address,
>this should pose no problems.
>
>On systems where a pointer is composed of a segment identifier
>and an offset, the compiler might arrange that the "normal"
>operations would never change the segment identifier.
>Comparisons could then be done by just comparing the
>segment identifier and offset. If two pointers to the same object
>have different segment identifiers, then the programmer must have
>applied some un"normal" operation, so it's OK if the pointers
>compare unequal.
This is exactly what C compilers for DOS systems currently do.
It should be straightforward to apply the same approach for the
386 memory models where pointers are 48 bits.
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Mon, 21 Dec 1992 12:50:09 GMT Raw View
sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
>In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
>>
>> Two pointers to the same object compare equal. If two pointers
>
>...but nowhere do I see a statement that (p == q) ==> p and q point
>to the same object, even if p and q are the same type.
This is apparently an oversight, an unintend omission.
The ANSI C standard includes such a guarantee, so I am told,
so C compatability requires that this hold at least for C++ objects
that are also C objects. (Though it needn't apply for empty
structs/classes, for example, since C doesn't allow empty structs.)
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: pkt@lpi.liant.com (Scott Turner)
Date: Mon, 21 Dec 1992 18:18:08 GMT Raw View
In article <1gt9qjINNsrr@darkstar.UCSC.EDU>, daniel@cse.ucsc.edu (Daniel R. Edelson) writes:
> There's also a problem regarding inline functions.
> Specifically, under common file-based C++ implementations,
> the address of an inline function can vary between
> compilation units. Thus, the requirement from
> Ansi C (Sec 3.3.9)
> ``If two pointers to function types ... both point to
> the same function, they compare equal.''
> is false under common C++ implementations.
An inline function (such as you speak of) has internal linkage.
Its definition is in the header file, so internal linkage implies
that there is a different function in each compilation unit.
The requirement from standard C is honored.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA (508) 872-8700
UUCP: uunet!lpi!pkt Internet: pkt@lpi.liant.com
Author: fjh@munta.cs.mu.OZ.AU (Fergus James HENDERSON)
Date: Mon, 21 Dec 1992 19:17:55 GMT Raw View
daniel@cse.ucsc.edu (Daniel R. Edelson) writes:
>There's also a problem regarding inline functions.
>Specifically, under common file-based C++ implementations,
>the address of an inline function can vary between
>compilation units. Thus, the requirement from
>Ansi C (Sec 3.3.9)
> ``If two pointers to function types ... both point to
> the same function, they compare equal.''
>is false under common C++ implementations.
Actually, these implementations are correct. Inline non-member functions have
internal linkage, and thus an inline function in one compilation unit
is a different function to even a lexically identical inline function in
a different compilation unit. (Inline member functions however are a
whole different can of worms.)
Does ANSI C require that pointers to different functions
will compare unequal? If so, it is not the common C++ implementations
that are the difficulty, it is the more sophisticated C++ implementations
(such as Borland C++ with the "Smart Inlines" flag enabled) that use
smart linkers or other techniques to avoid generating multiple copies
of inline functions.
Personally I believe that the default internal linkage for inline
non-member functions was a mistake, brought about by letting the
original implementation dictate too strongly the semantics of the
language. Even if it is perhaps too late to change this, the ANSI C++
standard should definitely not require that pointers to different
functions compare unequal, because that would prevent a useful
optimization, with no real gain. It should be enough to require
that if f and g are function pointers of the same type for which
f==g, then (*f)(...) has the same effect as (*g)(...).
--
Fergus Henderson fjh@munta.cs.mu.OZ.AU
This .signature virus is a self-referential statement that is true - but
you will only be able to consistently believe it if you copy it to your own
.signature file!
Author: pkt@lpi.liant.com (Scott Turner)
Date: Mon, 21 Dec 1992 18:48:46 GMT Raw View
In article <1992Dec18.202539.22728@ucc.su.OZ.AU>, maxtal@extro.ucc.su.OZ.AU (John MAX Skaller) writes:
> >"the result depends on the relative positions ... in the address
> >space." What does this mean?
>
> This means that the committee has committed a grave error.
> Too many Unix people. The ARM also commits this error in
> assuming the existence of *an* address space.
Implicit smiley detected :-) It actually means that the committee adopted
the ARM's text as its base document and as the foundation of its working
paper. The committee has not yet addressed the shortcomings of the ARM's
5.9 and 5.10.
In article <18188@autodesk.COM> larsn@Autodesk.COM (Lars Nyman) writes:
> ARM specifies what a comparison of two pointers to objects should return
> IF:
> - the objects are the same
> - the objects are non-static members of same object
> - the objects are elements of the same array
>
> Otherwise, the pointer comparison is implementation dependent.
>
>
> So, if I have pointers to two different objects the result of comparing
> them is implementation defined !?!
> Thus, I cannot even trust that a '!=' test will return 1 for two objects
> that are not the same !
>
> This must surely be wrong... can somebody, please, correct me and explain
> what I'm overlooking.
This problem has the same explanation. 5.9 and 5.10 need work
before they're suitable for a standard. I avoid them when trying
to understand the meaning of pointer comparison, and get out my C standard.
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA (508) 872-8700
UUCP: uunet!lpi!pkt Internet: pkt@lpi.liant.com
Author: jimad@microsoft.com (Jim Adcock)
Date: 19 Dec 92 00:18:51 GMT Raw View
In article <1992Dec17.151642.9954@bcrka451.bnr.ca> sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
|>4) If two pointers p and q (of the same type) are obtained through
|> sequences of "normal" operations, then
|>
|> p == q <==> p and q point to the same object
|
|I could not find this statement in the current wording. Is there a
|reason why the current wording is weaker than this?
Again, a simple counterexample is as follows:
#include <stdio.h>
class A {};
class B : public A
{
public:
A a;
};
main()
{
B b;
A* pb = &b;
A* pa = &(b.a);
if (pb == pa)
printf("equality of two legal ptrs of the same type pointing"
"at different objects");
return 0;
}
Again, my claim is that this is perfectly legal C++ code, which is commonly
implemented in some C++ compilers such that the equality test does
test true. On the contrary, for the test to not prove true would
mean that the empty base class part has to be implemented by the compiler
using gratuitous padding, and gratuitous padding is an anathema to
traditional C/C++ implementation.
Author: sjm@bcrki65.bnr.ca (Stuart MacMartin)
Date: Tue, 22 Dec 1992 14:02:12 GMT Raw View
In article <1992Dec19.001851.22116@microsoft.com> jimad@microsoft.com (Jim Adcock) writes:
>In article <1992Dec17.151642.9954@bcrka451.bnr.ca> sjm@bcrki65.bnr.ca (Stuart MacMartin) writes:
>|>4) If two pointers p and q (of the same type) are obtained through
>|> sequences of "normal" operations, then
>|>
>|> p == q <==> p and q point to the same object
>|
>|I could not find this statement in the current wording. Is there a
>|reason why the current wording is weaker than this?
>
>Again, a simple counterexample is as follows:
>
[Class A with no state; class B is derived from A and contains an A.
Compare pointer to base A of B against pointer to member A of B]
1. I would be annoyed if there was gratuitous padding here.
I want to be able to have T_interface and T_implementation : public T_interface.
2. Perhaps there is a philosophical argument that might resolve this issue.
If two objects have the same interface but no state (or constant state), and
they have the same lifetime, are they in fact the same object? Or, perhaps,
can they be treated as if they are the same object?
The rule about new returning different addresses is needed because the objects
have different lifetimes and so part of their state (their existence) differs,
and the objects can be observed to be different. In your example, I see no way
of determining which A is which other than by looking at the pointers. Can I
even tell if there really are two As? Mightn't one have been optimized away?
Maybe someone who feels strongly that there is only one 1, or conversely that
there are an infinite number of identical 1s can comment. Seems like a
similar concept.
Stuart
--
: Stuart MacMartin email: sjm@bnr.ca :
: Bell-Northern Research phone: (613) 763-5625 :
: PO Box 3511, Stn C, Ottawa, K1Y-4H7, CANADA Standard disclaimers apply. :
Author: pkt@lpi.liant.com (Scott Turner)
Date: Tue, 22 Dec 1992 17:43:27 GMT Raw View
In article <1992Dec19.001851.22116@microsoft.com>, jimad@microsoft.com (Jim Adcock) writes:
> On the contrary, for the test to not prove true would
> mean that the empty base class part has to be implemented by the compiler
> using gratuitous padding, and gratuitous padding is an anathema to
> traditional C/C++ implementation.
"Gratuitous" is your own judgment. Some of us disagree.
Moreover, such padding is in the C++ tradition. The ARM requires padding
in two places, where the principal intent is to support
p and q point to different objects implies p!=q
1. 5.3.2 "The size of any class object is larger than zero."
2. 5.3.3 "This implies that an operator new() can be called with an
argument zero. In this case, a pointer to an object is returned.
Repeated such calls return pointers to different objects."
[An example follows to demonstrate that the intent is that
distinguishable pointers values be returned.]
--
Prescott K. Turner, Jr.
Liant Software Corp. (developers of LPI languages)
959 Concord St., Framingham, MA 01701 USA (508) 872-8700
UUCP: uunet!lpi!pkt Internet: pkt@lpi.liant.com
Author: pat@frumious.uucp (Patrick Smith)
Date: Thu, 17 Dec 1992 01:56:56 GMT Raw View
(I hope nobody minds my changing the subject line to something
a little more succinct.)
While responding to a previous posting, I looked up what the
draft C++ standard (the September 17 version) had to say about
pointer comparisons. Here's an extract from section 5.9:
Pointers to objects or functions of the same type (after pointer
conversions) may be compared; the result depends on the relative
positions of the pointed-to objects or functions in the address
space.
Two pointers to the same object compare equal. If two pointers
point to nonstatic data members of the same object, the pointer
to the later declared member compares higher provided the two
members [are] not separated by an access-specifier label (11.1)
and provided their class is not a union. If two pointers
point to nonstatic members of the same object separated by an
access-specifier label (11.1) the result is unspecified.
If two pointers point to data members of the same union, they
compare equal (after conversion to void*, if necessary).
If two pointers point to elements of the same array or one beyond
the end of the array, the pointer to the object with the higher
subscript compares higher. Other pointer comparisons are
implementation dependent.
Unfortunately, my copy of the C standard isn't at all handy, so
I can't compare with what it says.
Some of this is quite unclear to me.
"Pointers ... may be compared". Does this mean any pair of pointers
may be compared, or some pairs may be compared? It certainly suggests
"any pair" to me, but some might interpret it as "some pairs".
"the result depends on the relative positions ... in the address
space." What does this mean? Must one convert the pointers into
actual addresses and return the result of comparing those addresses?
Probably not, given that "[o]ther pointer comparisons are
implementation dependent." Maybe one is to convert the pointers
into addresses and apply some (arbitrary) function to those addresses?
If so, why would one want such a condition? What happens if there's
more than one address space? This clause seems reasonable to me if
interpreted as "the general intent of pointer comparison is to compare
addresses", but perhaps it's not suitable as part of the specification
of the language.
"If two pointers point to elements of the same array ...".
What if they point to members of elements?
struct X { int a; int b; };
X x[2];
Must it be true that &x[0].a < &x[1].a? What about &x[0].b < &x[1].a?
"If two pointers point to data members of the same union, they compare
equal (after conversion to void*, if necessary)." This one seems
clear enough, but may have a trap for the unwary.
class A {};
class B {};
class C : public A, public B {};
union D {
B b;
C c;
} d;
Here the comparison &d.c == &d.b is legal, but might return 0
(it compares pointers to d.b and the B part of d.c). To compare
pointers to d.c and d.b themselves, one should explicitly cast
to void*. Ouch.
Let me try to be constructive for a change. Would something
similar to the following be reasonable? (It would clearly need
much more careful wording and attention to details.)
1) Any two pointers to the same type may be compared, with any of
the relational operators.
2) In general, the results of the comparisons need not have anything
to do with the objects to which the pointers point. For example,
it is possible that p and q point to the same object, but p != q.
(But see below.)
3) The relational operators define a total ordering on the set of
pointers of each type. (All the normal rules, including
transitivity.)
4) If two pointers p and q (of the same type) are obtained through
sequences of "normal" operations, then
p == q <==> p and q point to the same object
If p and q point to elements of the same array, or to
subobjects of _different_ elements of the same array,
then they compare the same way as the indexes of the
elements in the array.
As above when p and q point to members of the same (non-union)
object.
If p and q point to members of the same union object, then
p == q if either
- the members have the same type (ignoring const and volatile)
or
- p and q are void* pointers and were obtained by converting
directly from pointers to the types of the members, with
no intermediate conversions (again ignore const and
volatile everywhere).
If neither of these conditions is met, p == q is
implementation-defined.
For rule (4), "normal" operations would include things such as
the built-in & operator, adding integers to pointers to array
elements, normal casts (eg. derived class pointer to base class
pointer), and calls to standard library functions. It would
specifically exclude casts whose meaning is not defined by the
standard (eg. casting an integer to a pointer) and calling an
extern "C" function. (Actually, one could develop a notion of a
C function which only does "normal" operations and permit
calling such a function. (Is there already a concept of strictly
conforming C function, as opposed to program?))
On systems where a pointer can be treated as an integer address,
this should pose no problems.
On systems where a pointer is composed of a segment identifier
and an offset, the compiler might arrange that the "normal"
operations would never change the segment identifier.
Comparisons could then be done by just comparing the
segment identifier and offset. If two pointers to the same object
have different segment identifiers, then the programmer must have
applied some un"normal" operation, so it's OK if the pointers
compare unequal.
One might add a library function sameObject(p,q) which would
indicate whether p and q point to the same object, no matter
how p and q were obtained.
If we ignore the question of how much existing code this would
break, is this a reasonable suggestion?
And how much existing code would this break (that isn't already
broken)? Note that it doesn't break any code that restricts
itself to "normal" operations.
--
Patrick Smith
uunet.ca!frumious!pat
pat%frumious.uucp@uunet.ca
Author: sjm@bcrki65.bnr.ca (Stuart MacMartin)
Date: Thu, 17 Dec 1992 15:16:42 GMT Raw View
In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
>
> Two pointers to the same object compare equal. If two pointers
...but nowhere do I see a statement that (p == q) ==> p and q point
to the same object, even if p and q are the same type.
Is it possible for two objects of the same type to be in different
segments and compare equal?
>"Pointers ... may be compared". Does this mean any pair of pointers
>may be compared, or some pairs may be compared? It certainly suggests
>"any pair" to me, but some might interpret it as "some pairs".
I interpreted this as "a compiler is permitted to allow comparisons of
pointers not specified in this document", but I use the word "may" to
mean "is allowed to", not "might", and I don't know the meaning of
"may" in legalese. So yes, this wording is unclear to normal programmers.
>Let me try to be constructive for a change. Would something
>similar to the following be reasonable? (It would clearly need
>much more careful wording and attention to details.)
>
>1) Any two pointers to the same type may be compared, with any of
> the relational operators.
>
>2) In general, the results of the comparisons need not have anything
> to do with the objects to which the pointers point. For example,
> it is possible that p and q point to the same object, but p != q.
> (But see below.)
Note that this provides your counterexample for
(p == q) <==> (ptrcmp(p,q) == 0)
Also, I would expect OODBMSs to use object ids to determine the ordering,
so if p and q point to the same object but p and q are of different types,
we might allow ptrcmp(p,q) == 0.
Or should equality mean "the same object and the same type"? This
might be unnatural if the OODBMS has a different concept of type than
C++; for example, if the type of the OODBMS handle (smart pointer) is
used to say "use this object as if it were an object of type T" instead
of the typical C++ usage: "use the type T part of this object". In the
former case, the objects pointed to by the two pointers really are the same,
even if one pointer has a restricted view of it.
>3) The relational operators define a total ordering on the set of
> pointers of each type. (All the normal rules, including
> transitivity.)
Is this possible? Mightn't some objects of one type be in one segment
and some in another? (Perhaps I should say "practical", not "possible").
>4) If two pointers p and q (of the same type) are obtained through
> sequences of "normal" operations, then
>
> p == q <==> p and q point to the same object
I could not find this statement in the current wording. Is there a
reason why the current wording is weaker than this?
What do you mean by "normal" operations?
What are examples of "abnormal" operations?
>One might add a library function sameObject(p,q) which would
>indicate whether p and q point to the same object, no matter
>how p and q were obtained.
Is this necessary if we have ptrcmp? If we like the name ptrcmp, shouldn't
we like the name ptreq? If we like sameObject, perhaps we should like
cmpUsingObjectOrder(p,q)?
Also, if p = (Base *)q, should sameObject(p,q) be 1?
Stuart
--
: Stuart MacMartin email: sjm@bnr.ca :
: Bell-Northern Research phone: (613) 763-5625 :
: PO Box 3511, Stn C, Ottawa, K1Y-4H7, CANADA Standard disclaimers apply. :
Author: daniel@cse.ucsc.edu (Daniel R. Edelson)
Date: 18 Dec 92 19:46:27 GMT Raw View
In article <1992Dec18.181029.1061@taumet.com> steve@taumet.com (Steve Clamage) writes:
>
>Right. In the C Standard, it is stated explicitly that two pointers
>of the same type which compare equal point to the same object or
>function. There is no such statment for C++ in the ARM or in the
>current C++ Committee working draft.
>
>Steve Clamage, TauMetric Corp, steve@taumet.com
There's also a problem regarding inline functions.
Specifically, under common file-based C++ implementations,
the address of an inline function can vary between
compilation units. Thus, the requirement from
Ansi C (Sec 3.3.9)
``If two pointers to function types ... both point to
the same function, they compare equal.''
is false under common C++ implementations. In my view, this
suggests that perhaps it should be illegal to take the address
of an inline function.
Daniel Edelson
daniel@cse.ucsc.edu
Author: jimad@microsoft.com (Jim Adcock)
Date: 17 Dec 92 22:49:59 GMT Raw View
In article <BzDs2x.wA@frumious.uucp> uunet.ca!frumious!pat writes:
|"Pointers ... may be compared". Does this mean any pair of pointers
|may be compared, or some pairs may be compared? It certainly suggests
|"any pair" to me, but some might interpret it as "some pairs".
It means the compiler *will* accept code containing pointer comparisons
as specified.
|"the result depends on the relative positions ... in the address
|space." What does this mean? Must one convert the pointers into
|actual addresses and return the result of comparing those addresses?
The meaning of "address space" is *as given in the specification.*
IE the wording about the ordering of objects in an array, and members
within a common declaration section. The meaning of "address space" as
defined by a conforming implementation need not be the same meaning of
"address space" as implemented by the underlying CPU. A simple example
of this is the case of a C++ implementation targeting a P-code machine
which in turn has a software-implemented virtual address scheme.
Yes people do write such implementation machines. "Address
Space" in this case refers to the *implementation* address space, not
the *CPU* address space. This in turn says its the *implementation* not
the CPU that defines the meaning of these things. The implementation simply
has to implement its address space so that it meets the stated requirements
of the standard. Another [weaker] example of this is a 486 CPU which
can have a 48-bit virtual address space, but has *implementations* running
assuming one or more cases [possibly within one program] of the following
*implementation* models: 0:16, 2x0:16, 16:16, 0:32, 16:32, and 16+32.
If any implementation memory model meets the explicit requirements of
the language specification, then such *is* the meaning of "address space".
|"If two pointers point to elements of the same array ...".
|What if they point to members of elements?
Then you are allowed to *make* the comparison, but the *results* of the
comparison are *implementation defined* since the results of such a
comparison are not otherwise called out in the spec.
| struct X { int a; int b; };
| X x[2];
|
|Must it be true that &x[0].a < &x[1].a?
Nope.
What about &x[0].b < &x[1].a?
Nope.
The specification makes no such requirement, thus there is no such
requirement.
|3) The relational operators define a total ordering on the set of
| pointers of each type. (All the normal rules, including
| transitivity.)
Not reasonable for all the reasons already discussed.
|On systems where a pointer is composed of a segment identifier
|and an offset, the compiler might arrange that the "normal"
|operations would never change the segment identifier.
Such a compiler would not be useful on implementations requiring
the segment identifier change.
|If we ignore the question of how much existing code this would
|break, is this a reasonable suggestion?
No, because you would be ignoring the question of how much existing
code this would break. Including system implementations.
|And how much existing code would this break (that isn't already
|broken)? Note that it doesn't break any code that restricts
|itself to "normal" operations.
"Normal" depends very much on what one is used to. You expectations
appear very "unnormal" to me.
Code that depends on implementation details of address implementation
has repeatedly proven to be very fragile in the past. Let's not get
sucked into depending on details of address implementaion again. Let's
give ourselves the freedom to run optimally on whatever machine appear
today and in the future.