Topic: Aliasing


Author: James.Kanze@dresdner-bank.com
Date: 1999/01/27
Raw View
In articlIn article <78ll0s$12k$1@engnews2.Eng.Sun.COM>,
  stephen.clamage@Eng.sun.com (Steve Clamage) wrote:

> When you write, for example,
>  T* p = (T*) malloc(sizeof(T));
> you don't have an object until you create an object of type T
> (or possibly of some other type) in the storage by using one of its
> constructors, such as the copy constructor.

What about objects with trival constructors?  If T were int, for
example, I would expect to be able to *assign* through p without
explicitly calling the constructor, i.e.:

    *p = 5 ;

is legal, I don't have to write:

    new ( p ) int( 5 ) ;

This is definitly *not* the case for objects with a non-trivial
constructor, however.  For such objects, I *must* use placement new to
construct the object before any access, including assignment.

Furthermore, I believe that something like the following is legal:

    void*           p = malloc( max( sizeof( int ) , sizeof( double ) ) ) ;
    int*            pi = (int*)( p ) ;
    double*         pd = (double*)( p ) ;
    *pi = 5 ;
    //  ...
    *pd = 5.0 ;

I suspect that this is what Bill Wade was referring to when he said that
the memory returned was an implicit union of all types that fit.  I
also think that the union rule of only being able to access the last
type written is also valid here; a sequence like the following is
illegal:

    *pd = 5.0 ;
    cout << *pi ;

--
James Kanze                                           GABI Software, S   rl
Conseils en informatique orient    objet  --
                          --  Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr          mailto: James.Kanze@dresdner-bank.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/01/27
Raw View
James.Kanze@dresdner-bank.com wrote in message
<78nat02gr$1@nnrp1.dejanews.com>...
> [double* pd and int* pi pointing at same location, not in a union] I
>also think that the union rule of only being able to access the last
>type written is also valid here; a sequence like the following is
>illegal:
>
>    *pd = 5.0 ;
>    cout << *pi ;

You don't need the union rule for this case.  3.10 says (paraphrased and
simplified) that you can't reliably read *pi unless the last write to that
location was as an int or as a char.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/28
Raw View
In article <78nld8$1q$1@uuneo.neosoft.com>,
  "Bill Wade" <bill.wade@stoner.com> wrote:
> James.Kanze@dresdner-bank.com wrote in message
> <78nat02gr$1@nnrp1.dejanews.com>...
> > [double* pd and int* pi pointing at same location, not in a union] I
> >also think that the union rule of only being able to access the last
> >type written is also valid here; a sequence like the following is
> >illegal:
> >
> >    *pd = 5.0 ;
> >    cout << *pi ;
>
> You don't need the union rule for this case.  3.10 says (paraphrased and
> simplified) that you can't reliably read *pi unless the last write to that
> location was as an int or as a char.

I came to the same conclusion... and I think thats the intent, but Im not sure
any more.

3.10 refers to the "dynamic type" of the object. The corresponding clause
from C9X talks about the "effective type", which is defined as the declared
type, or the last non-character write. The definition of "dynamic type" in
the C++ standard does not seem to cover this. Even with C9X its not clear to
me what a partial write does:

X1 *p1 = (X1*)malloc(sizeof(X1));
p1->x1 = 5;
// is the effective type of the memory referenced by *p1 now X1,
// or is it just the memory referenced by p1->x1 which has type int?

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/29
Raw View
markw65@my-dejanews.com wrote:
>
> In article <36A8DF9C.4309@pratique.fr>,
>   Valentin Bonnard <bonnardv@pratique.fr> wrote:
> > markw65@my-dejanews.com wrote:
> >
> > It's a matter of taste.
> >
> > > So I repeat the question: Is there a conforming program such that the
> > > assumption is invalid. Im thinking along the lines of bizarre unions etc
> > > where x1 & x2 have managed to land on top of each other.
> >
> > As you want. You define you expect from programs, you document it,
> > and you add a flag because some users might not (read: won't) like it.
>
> I dont follow. I want the compiler to generate correct code for standard
> conforming programs.

There is a mathematical set, just an intuitive notion.

> I dont care what it produces for non-conforming programs.
> What do you want me to document, and what is the flag for?

What you do. Which programs are accepted and which programs
may cause strange effects.

> > Are you really expecting the std to define what is undefined
> > behaviour ? You are overating the std then.
>
> No. I just want to establish the extent to which I can apply type based
> aliasing.

Then you are overrating the std.

Seriously, who cares (except you, and perhaps me) ?

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/30
Raw View
markw65@my-dejanews.com wrote:

> I came to the same conclusion... and I think thats the intent, but Im not sure
> any more.

You seem to imply that there was an intent. <g>

> 3.10 refers to the "dynamic type" of the object. The corresponding clause
> from C9X talks about the "effective type",

The notion of dynamic type is badly defined in C++, it only works
fine for non PODs. I have reported the problem informally to some
core WG members, who weren't really interrested in that because it
doesn't break existing compilers.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Bill Wade" <bill.wade@stoner.com>
Date: 1999/01/26
Raw View
Steve Clamage wrote in message <78fki3$9iu$1@engnews2.Eng.Sun.COM>...

>> [ Example which accesses members of a union in the wrong order ]
>That is not a legitimate use. The results of attempting to
>treat a union as more than one of its members at the same time
>has undefined results.


I'll assume you're talking about the restrictions of 9.5.  Do those
restrictions apply to the memory returned by malloc()?  Such memory is
normally treated as a union of everything that fits, but I can't find any
words in the standard that say it has the same access requirements as a
"real" union.

struct T1 { ... int i1; ... };    // POD
struct T2 { ... int i2; ... };    // POD

void* p = malloc(BIG_ENOUGH);

if(p && offsetof(T1, i1) == offsetof(T2, i2))
{
  ((T1*)p)->i1 = 7;
  assert((T2*)p)->i2 == 7);
}

Does this result in undefined behavior?  I think it should, but I don't see
how the standard says so.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/26
Raw View
In article <36A8DF9C.4309@pratique.fr>,
  Valentin Bonnard <bonnardv@pratique.fr> wrote:
> markw65@my-dejanews.com wrote:
>
> > Seems you have completely missed the point... Im trying to implement the
> > strongest possible type based alias analysis without breaking valid code. I
> > _know_ that it would take some pretty monstrous code to alias those two
> > values - I even gave an example (which, by the way, has a pretty good chance
> > of causing p1->x1 & p2->x2 to have the same address, unlike your example,
> > which merely causes p1 & p2 to have the same address).
>
> It's a matter of taste.
>
> > So I repeat the question: Is there a conforming program such that the
> > assumption is invalid. Im thinking along the lines of bizarre unions etc
> > where x1 & x2 have managed to land on top of each other.
>
> As you want. You define you expect from programs, you document it,
> and you add a flag because some users might not (read: won't) like it.

I dont follow. I want the compiler to generate correct code for standard
conforming programs. I dont care what it produces for non-conforming programs.
What do you want me to document, and what is the flag for?

>
> Are you really expecting the std to define what is undefined
> behaviour ? You are overating the std then.
>

No. I just want to establish the extent to which I can apply type based
aliasing. The odd thing that strikes me about the example I gave, is that if I
change it a little:

X2 x2;

X1 foo(X1 *p1, X2 *p2)
{
 p1->x1 = 0;
 *p2 = x2;
 return *p1;
}

The clause on type based aliasing now ensures that, for a conforming program,
the x1 field of the returned X1 object is zero. (A store through an lvalue of
type X2 cannot alter an object of type X1, since neither contains a subobject
of the other's type).

So I think I may have the answer to my own question...

In the original example, p2->x2 is equivalent to (*p2).x2, so in addtion to
accessing the stored value of the x2 field as a long (my original assumption)
it also accesses the stored value of *p2 as an X2, in which case the type
based aliasing clause applies, and no aliasing is allowed.

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/26
Raw View
In article <78igli$dtn$1@uuneo.neosoft.com>, Bill Wade
<bill.wade@stoner.com> writes
>void* p = malloc(BIG_ENOUGH);
>
>if(p && offsetof(T1, i1) == offsetof(T2, i2))
>{
>  ((T1*)p)->i1 = 7;
>  assert((T2*)p)->i2 == 7);
>}
>
>Does this result in undefined behavior?  I think it should, but I don't see
>how the standard says so.

Well we are in C++ so raw memory is just that.  You do not have an
object until its ctor has been called.  Just changing the type of a
pointer isn't enough, I think.  Though perhaps it might be more
intersting in C that lacks the concept of ctor's.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/01/26
Raw View
In article <OGPq2.1197$3W4.211141@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
> >That is not a legitimate use. The results of attempting to
> >treat a union as more than one of its members at the same time
> >has undefined results.
>
> Then maybe I don't understand what "legitimate" means. I'm describing
> behavior that I've observed with many compilers.
>
> >>ie can I assume the following function returns 0?
> >>
> >>int foo(X1 *p1, X2 *p2)
> >>{
> >> p1->x1 = 0;
> >> p2->x2 = 1;
> >> return p1->x1;
> >>}
>
> (There's an apparent exception for POD-members having the
> same initial sequence, but that case doesn't have any of
> the problems under discussion.)
>
> The original poster's foo function, which, as I understood it, is the
> problem under discussion, doesn't know the proximity or relationship between
> *p1 and *p2 or whether they employ unions, POD, or whatever. I've provided
> one legitimate example wherein the answer to his question is "no." There are
> others.

What the original poster's foo function knows is irrelevant.  Both C and
C++ make it undefined behavior to access any member of a union except
the last one written. Regardless of how the access occurs.

--
James Kanze                                           GABI Software, S   rl
Conseils en informatique orient    objet  --
                          --  Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr          mailto: James.Kanze@dresdner-bank.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@Eng.sun.com (Steve Clamage)
Date: 1999/01/27
Raw View
"Bill Wade" <bill.wade@stoner.com> writes:

>Steve Clamage wrote in message <78fki3$9iu$1@engnews2.Eng.Sun.COM>...

>>> [ Example which accesses members of a union in the wrong order ]
>>That is not a legitimate use. The results of attempting to
>>treat a union as more than one of its members at the same time
>>has undefined results.

>I'll assume you're talking about the restrictions of 9.5.

Yes.

> Do those
>restrictions apply to the memory returned by malloc()?  Such memory is
>normally treated as a union of everything that fits,

No, memory returned by malloc or operator new() is not a union. It
is not an object at all. It is just raw memory. Raw memory is turned
into an object by its constructor. Every type has a constructor, if
only a conceptual one that does nothing.

When you write, for example,
 T* p = (T*) malloc(sizeof(T));
you don't have an object until you create an object of type T
(or possibly of some other type) in the storage by using one of its
constructors, such as the copy constructor.


>struct T1 { ... int i1; ... };    // POD
>struct T2 { ... int i2; ... };    // POD

>void* p = malloc(BIG_ENOUGH);

>if(p && offsetof(T1, i1) == offsetof(T2, i2))
>{
>  ((T1*)p)->i1 = 7;
>  assert((T2*)p)->i2 == 7);
>}

>Does this result in undefined behavior?  I think it should, but I don't see
>how the standard says so.

You have converted void* to a pointer of another type, then to a
third unrelated type. If you look up the rules on casts, you will
find the results of dereferencing any of the pointers are undefined.

But it is extremely likely that the code will work, because of the
usual object models used by C and C++ compilers.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: James.Kanze@dresdner-bank.com
Date: 1999/01/27
Raw View
In article <K0%p2.3$Fg3.341@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
> >ie can I assume the following function returns 0?
> >
> >int foo(X1 *p1, X2 *p2)
> >{
> > p1->x1 = 0;
> > p2->x2 = 1;
> > return p1->x1;
> >}
>
> Perhaps I'm missing the point, too. There are legitimate circumstances in
> which the second assignment could change the effect of the first. One of
> them is, as you guess, that some union includes members of type X1 and X2,
> and that p1 and p2 point to the x1 and x2 members of the X1 and X2 members
> of the union, which does not look bizarre to me at all.
>
>  union {
>      X1 xx1;
>      X2 xx2;
>  };
>  foo(&xx1, &xx2);

In this case, the return statement in the function results in undefined
behavior.

I didn't see the first posting, so I don't know if there were any
restrictions placed on the types X1 or X2.  If they are both PODS, I
don't think that there is any legal program where the return value would
not be zero, according to the standard.  If they are not, of course, and
X2::x2 is a type with a user defined operator=, then you aren't
guaranteed anything by the standard.

--
James Kanze                                           GABI Software, S   rl
Conseils en informatique orient    objet  --
                          --  Beratung in industrieller Datenverarbeitung
mailto: kanze@gabi-soft.fr          mailto: James.Kanze@dresdner-bank.com

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/01/25
Raw View
>That is not a legitimate use. The results of attempting to
>treat a union as more than one of its members at the same time
>has undefined results.

Then maybe I don't understand what "legitimate" means. I'm describing
behavior that I've observed with many compilers.

>>ie can I assume the following function returns 0?
>>
>>int foo(X1 *p1, X2 *p2)
>>{
>> p1->x1 = 0;
>> p2->x2 = 1;
>> return p1->x1;
>>}

(There's an apparent exception for POD-members having the
same initial sequence, but that case doesn't have any of
the problems under discussion.)

The original poster's foo function, which, as I understood it, is the
problem under discussion, doesn't know the proximity or relationship between
*p1 and *p2 or whether they employ unions, POD, or whatever. I've provided
one legitimate example wherein the answer to his question is "no." There are
others.
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/25
Raw View
Francis Glassborow <francis@robinton.demon.co.uk> writes:

>In article <788h7j$jhu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
>writes
>>> If using a pointer that points to an object of the wrong type isn't
>>> undefined behaviour I think we might all just give up.
>>
>>Im inclined to agree... but can you tell me how to read the standard in such a
>>way as to justify that remark?

>I think the answer lies in asking how a pointer variable can legally
>acquire a pointer value) It can be initialised at the point of
>declaration in which case either explicit or implict conversions must
>happen to ensure that the declared type and the value match.

Right.

> Or it can
>acquire a value via assignment, same requirementsa apply or possibly the
>value is modified via an increment or decremment operator or by using +=
>or -=.

Arithmetic doesn't change the type of the object being pointed to.

>These are the only places, I think, where you could get possibly
>mismatches without immediately incurring undefined behaviour.

>However C (and unless C++ overturns this explicitly, C++) requires that
>the value in a pointer provides a reference to an entity of the
>referenced type (6.1.2.5, para on pointer type).  From which I deduce
>that dereferencing a pointer whose value does not reference an entity of
>the referenced type will be undefined behaviour.

You can also look at the sections on the various casts. The only
way a pointer can be changed to point to a wrong type is via
a cast. ("Wrong" in the sense above.) In every case where such a
cast has defined results, the results of dereferencing the pointer
are undefined.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1999/01/25
Raw View
Al Stevens wrote:
>
> >That is not a legitimate use. The results of attempting to
> >treat a union as more than one of its members at the same time
> >has undefined results.
>
> Then maybe I don't understand what "legitimate" means. I'm describing
> behavior that I've observed with many compilers.

There are also many compilers where you will find the
following code "works":

enum what { init, test };

void foo(what action)
{
  int x;

  if (action == init)
    x=5;
  else
    assert(x==5);
}

int main()
{
  foo(init); // initialize x
  foo(test); // test x
}

It's nevertheless undefined behaviour.

>
> >>ie can I assume the following function returns 0?
> >>
> >>int foo(X1 *p1, X2 *p2)
> >>{
> >> p1->x1 = 0;
> >> p2->x2 = 1;
> >> return p1->x1;
> >>}
>
> (There's an apparent exception for POD-members having the
> same initial sequence, but that case doesn't have any of
> the problems under discussion.)
>
> The original poster's foo function, which, as I understood it, is the
> problem under discussion, doesn't know the proximity or relationship between
> *p1 and *p2 or whether they employ unions, POD, or whatever. I've provided
> one legitimate example wherein the answer to his question is "no." There are
> others.

Since it accesses members, it must have access to the full
definition of both types. And therefore the compiler knows
exactly:
- If one or both are PODs
- If both are layout compatible up to x1 and x2

Of course, it doesn't know in which way the objects have been
obtained - f.ex. if both are members of the same union.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: alanstokes@my-dejanews.com
Date: 1999/01/25
Raw View
In article <K0%p2.3$Fg3.341@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
> >ie can I assume the following function returns 0?
> >
> >int foo(X1 *p1, X2 *p2)
> >{
> > p1->x1 = 0;
> > p2->x2 = 1;
> > return p1->x1;
> >}
>
>  union {
>      X1 xx1;
>      X2 xx2;
>  };
>  foo(&xx1, &xx2);

That invokes undefined behaviour (see 9.5 para 1), and so returning 0 from foo
is perfectly reasonable. As indeed would returning 42.

The only exception would be if x1 and x2 are part of a common initial sequence
of POD-structs X1 and X2. This could be checked for at compile time (a nasty
special case, but perfectly doable), and the optimisation suppressed in such a
case.

- Alan

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: stephen.clamage@sun.com (Steve Clamage)
Date: 1999/01/25
Raw View
"Al Stevens" <alstevens@midifitz.com> writes:

>>That is not a legitimate use. The results of attempting to
>>treat a union as more than one of its members at the same time
>>has undefined results.

>Then maybe I don't understand what "legitimate" means. I'm describing
>behavior that I've observed with many compilers.

My dictionary defines "legitimate" as "being in accordance with
the law." The "law" in this case would be the C++ standard.
That's what I meant when I said the use was not legitimate --
it is not in accordance with the standard.

--
Steve Clamage, stephen.clamage@sun.com


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/25
Raw View
In article <OGPq2.1197$3W4.211141@newscene.newscene.com>, Al Stevens
<alstevens@midifitz.com> writes
>Then maybe I don't understand what "legitimate" means. I'm describing
>behavior that I've observed with many compilers.

None-the-less in order to get such behaviour I believe you have entered
the realm of 'undefined behaviour' IOW by doing this (writing through
one member of a union and reading via another) you have no guarantees
from the standard.  Of course in this case most compilers generate code
that behaves as you expect.  However there is no known way to code
defensively against te results of undefined behaviour.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/25
Raw View
In article <besBtjAU7Hq2Ewj6@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> In article <788h7j$jhu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
> writes
> >> If using a pointer that points to an object of the wrong type isn't
> >> undefined behaviour I think we might all just give up.
> >
> >Im inclined to agree... but can you tell me how to read the standard in such
a
> >way as to justify that remark?
>
> I think the answer lies in asking how a pointer variable can legally
> acquire a pointer value) It can be initialised at the point of
> declaration in which case either explicit or implict conversions must
> happen to ensure that the declared type and the value match.  Or it can
> acquire a value via assignment, same requirementsa apply or possibly the
> value is modified via an increment or decremment operator or by using +=
> or -=.  These are the only places, I think, where you could get possibly
> mismatches without immediately incurring undefined behaviour.
>
> However C (and unless C++ overturns this explicitly, C++) requires that
> the value in a pointer provides a reference to an entity of the
> referenced type (6.1.2.5, para on pointer type).  From which I deduce
> that dereferencing a pointer whose value does not reference an entity of
> the referenced type will be undefined behaviour.
>

But that doesnt quite work... if I malloc a block of memory, I can cast it to
any POD type I want, and (hopefully) use it with well defined consequences.
And presumably after finishing with it, I can cast it to some other type, and
again use it with well defined consequences.

So the question is, what happens if the uses overlap? ie the last read as
type1 occurs after the first write as type2? I note that C9x explicitly
covers this (the "type" of malloc'd memory matches the type of the last store
to it), so these overlapping uses are explicitly undefined behaviour. But I
can find no such statement in the C++ standard.

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/25
Raw View
In article <OGPq2.1197$3W4.211141@newscene.newscene.com>,
  "Al Stevens" <alstevens@midifitz.com> wrote:
> >That is not a legitimate use. The results of attempting to
> >treat a union as more than one of its members at the same time
> >has undefined results.
>
> Then maybe I don't understand what "legitimate" means. I'm describing
> behavior that I've observed with many compilers.
>
> >>ie can I assume the following function returns 0?
> >>
> >>int foo(X1 *p1, X2 *p2)
> >>{
> >> p1->x1 = 0;
> >> p2->x2 = 1;
> >> return p1->x1;
> >>}
>
> (There's an apparent exception for POD-members having the
> same initial sequence, but that case doesn't have any of
> the problems under discussion.)
>
> The original poster's foo function, which, as I understood it, is the
> problem under discussion, doesn't know the proximity or relationship between
> *p1 and *p2 or whether they employ unions, POD, or whatever. I've provided
> one legitimate example wherein the answer to his question is "no." There are
> others.

No, the original post (which was mine) stated that X1 & X2 were non-layout
compatible POD structs; while I suppose you could interpret that as having a
common initial sequence including x1/x2, then differing later on, it was
certainly intended to rule out the case where x1/x2 are part of a common
initial sequence. Which is the only case where your example is "legitimate".

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: "Al Stevens" <alstevens@midifitz.com>
Date: 1999/01/24
Raw View
>ie can I assume the following function returns 0?
>
>int foo(X1 *p1, X2 *p2)
>{
> p1->x1 = 0;
> p2->x2 = 1;
> return p1->x1;
>}

Perhaps I'm missing the point, too. There are legitimate circumstances in
which the second assignment could change the effect of the first. One of
them is, as you guess, that some union includes members of type X1 and X2,
and that p1 and p2 point to the x1 and x2 members of the X1 and X2 members
of the union, which does not look bizarre to me at all.

 union {
     X1 xx1;
     X2 xx2;
 };
 foo(&xx1, &xx2);
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/24
Raw View
In article <788h7j$jhu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
writes
>> If using a pointer that points to an object of the wrong type isn't
>> undefined behaviour I think we might all just give up.
>
>Im inclined to agree... but can you tell me how to read the standard in such a
>way as to justify that remark?

I think the answer lies in asking how a pointer variable can legally
acquire a pointer value) It can be initialised at the point of
declaration in which case either explicit or implict conversions must
happen to ensure that the declared type and the value match.  Or it can
acquire a value via assignment, same requirementsa apply or possibly the
value is modified via an increment or decremment operator or by using +=
or -=.  These are the only places, I think, where you could get possibly
mismatches without immediately incurring undefined behaviour.

However C (and unless C++ overturns this explicitly, C++) requires that
the value in a pointer provides a reference to an entity of the
referenced type (6.1.2.5, para on pointer type).  From which I deduce
that dereferencing a pointer whose value does not reference an entity of
the referenced type will be undefined behaviour.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1999/01/24
Raw View
markw65@my-dejanews.com wrote:

> Seems you have completely missed the point... Im trying to implement the
> strongest possible type based alias analysis without breaking valid code. I
> _know_ that it would take some pretty monstrous code to alias those two
> values - I even gave an example (which, by the way, has a pretty good chance
> of causing p1->x1 & p2->x2 to have the same address, unlike your example,
> which merely causes p1 & p2 to have the same address).

It's a matter of taste.

> So I repeat the question: Is there a conforming program such that the
> assumption is invalid. Im thinking along the lines of bizarre unions etc
> where x1 & x2 have managed to land on top of each other.

As you want. You define you expect from programs, you document it,
and you add a flag because some users might not (read: won't) like it.

Are you really expecting the std to define what is undefined
behaviour ? You are overating the std then.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/24
Raw View
In article <78afvh$8sb@sis.cambridge.arm.com>,
  scott douglass <sdouglass%_%junk@_.arm.com> wrote:
>
> markw65@my-dejanews.com wrote:
> > So I repeat the question: Is there a conforming program such that the
> > assumption is invalid. Im thinking along the lines of bizarre unions etc
> > where x1 & x2 have managed to land on top of each other.
> >
> > ie can I assume the following function returns 0?
> >
> > int foo(X1 *p1, X2 *p2)
> > {
> >  p1->x1 = 0;
> >  p2->x2 = 1;
> >  return p1->x1;
> > }
>
> Is this the bizarre union example you wanted (or didn't want)?
>
> struct X1 { int x1; };
> struct X1a { char a2[4]; X1 x1a; };
> struct X2 { char a2[4]; int x2; /* ... */ };
> union U { X1a u1; X2 u2; };
>
> // for some compilers offsetof(U, u1.x1a.x1) == offsetof(U, u2.x2)
>
> int f() { U u; return foo(&u.u1.x1a, &u.u2); }
>
> I guess my interpretation is that the aliasing is legal and the optimization
is
> not.  Too bad, I wish it was the other way.

Actually, I dont think this does it. According to 9.5.1 only one member of a
union can be active at any given time. So storing to one member, and reading
back a different member is not allowed (unless x1 & x2 are part of a common
initial sequence). So your program invokes undefined behaviour, and returning
0 from the function is fine... (and indeed preferable to having your hard
disk formated :-)

So the best I can come up with is this:

char *p = malloc(sizeof(X1) + sizeof(X2));
X1 *p1 = (X1*)(p + offsetof(X2, x2));
X2 *p2 = (X2*)(p + offsetof(X1, x1));
// assume alignment requirements are met
foo(p1, p2); // legal? or do the same rules apply as for unions?

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: clamage@Eng.Sun.COM (Steve Clamage)
Date: 1999/01/24
Raw View
"Al Stevens" <alstevens@midifitz.com> writes:

>>ie can I assume the following function returns 0?
>>
>>int foo(X1 *p1, X2 *p2)
>>{
>> p1->x1 = 0;
>> p2->x2 = 1;
>> return p1->x1;
>>}

>Perhaps I'm missing the point, too. There are legitimate circumstances in
>which the second assignment could change the effect of the first. One of
>them is, as you guess, that some union includes members of type X1 and X2,
>and that p1 and p2 point to the x1 and x2 members of the X1 and X2 members
>of the union, which does not look bizarre to me at all.

> union {
>     X1 xx1;
>     X2 xx2;
> };
> foo(&xx1, &xx2);

That is not a legitimate use. The results of attempting to
treat a union as more than one of its members at the same time
has undefined results.

(There's an apparent exception for POD-members having the
same initial sequence, but that case doesn't have any of
the problems under discussion.)

--
Steve Clamage, stephen.clamage@sun.com
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/21
Raw View
The standard (3.10) states:

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
15If  a program attempts to access the stored value of an object through
  an lvalue of other than one of the following  types  the  behavior  is
  undefined48):

  --the dynamic type of the object,

  --a cv-qualified version of the dynamic type of the object,

  --a type that is the signed or  unsigned  type  corresponding  to  the
    dynamic type of the object,

  --a  type  that  is the signed or unsigned type corresponding to a cv-
    qualified version of the dynamic type of the object,

  --an aggregate or union type that includes one of  the  aforementioned
    types  among its members (including, recursively, a member of a sub-
    aggregate or contained union),

  --a type that is a (possibly cv-qualified)  base  class  type  of  the
    dynamic type of the object,

  --a char or unsigned char type.

  _________________________
  48) The intent of this list is to specify those circumstances in which
  an object may or may not be aliased.
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

If I have two (non-layout compatible) POD structs

struct X1 { /* ... */ int x1; /* ... */ };
struct X2 { /* ... */ int x2; /* ... */ };

And two pointers

X1 *p1;
X2 *p2;

I would like to be able to assume that p1->x1 does not alias p2->x2, but I
cant justify that based on the above quote.

The problem I am seeing is that p2->x2 is an lvalue of type int. The object
pointed to by p1 is an aggregate which contains an int, so p2->x2 is explictly
allowed to access the stored value of the object pointed to by p1...

Im hoping that Im not reading it correctly, or that there is something
elsewhere in the standard which does make the assumption valid.

Im assuming that the assumption is good for non-POD.

Im also aware that I could set p1 = (X1*)((char*)&p2->x2 - offsetof(X1, x1)).
The question is whether doing so invokes undefined/implementation defined
behaviour.

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1999/01/21
Raw View
In article <785ck9$qlu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
writes
>If I have two (non-layout compatible) POD structs
>
>struct X1 { /* ... */ int x1; /* ... */ };
>struct X2 { /* ... */ int x2; /* ... */ };
>
>And two pointers
>
>X1 *p1;
>X2 *p2;
>
>I would like to be able to assume that p1->x1 does not alias p2->x2, but I
>cant justify that based on the above quote.

But I think you are misconstruing the meaning of the quote.  What it
says is that anything other than those things in the list will result in
undefined behaviour, it does NOT say that doing the things in the list
will work.

However how is your program going to provide such aliased access?  Only,
as far as I can see, via some monstrous piece of coding such as:

X1 x1, *p1 = &x1;
X2 *p2 = (X1 *)(void *)p1;

>
>The problem I am seeing is that p2->x2 is an lvalue of type int. The object
>pointed to by p1 is an aggregate which contains an int, so p2->x2 is explictly
>allowed to access the stored value of the object pointed to by p1...

No, I do not think it is explcitly allowed to unless you have already
introduced undefined behaviour in some other way.

>
>Im hoping that Im not reading it correctly, or that there is something
>elsewhere in the standard which does make the assumption valid.

Write some well-formed code that exhibits what you think is a problem.
>
>Im assuming that the assumption is good for non-POD.
>
>Im also aware that I could set p1 = (X1*)((char*)&p2->x2 - offsetof(X1, x1)).
>The question is whether doing so invokes undefined/implementation defined
>behaviour.

If using a pointer that points to an object of the wrong type isn't
undefined behaviour I think we might all just give up.


Francis Glassborow      Chair of Association of C & C++ Users
64 Southfield Rd
Oxford OX4 1PA          +44(0)1865 246490
All opinions are mine and do not represent those of any organisation
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: markw65@my-dejanews.com
Date: 1999/01/22
Raw View
Seems you have completely missed the point... Im trying to implement the
strongest possible type based alias analysis without breaking valid code. I
_know_ that it would take some pretty monstrous code to alias those two
values - I even gave an example (which, by the way, has a pretty good chance
of causing p1->x1 & p2->x2 to have the same address, unlike your example,
which merely causes p1 & p2 to have the same address).

So I repeat the question: Is there a conforming program such that the
assumption is invalid. Im thinking along the lines of bizarre unions etc
where x1 & x2 have managed to land on top of each other.

ie can I assume the following function returns 0?

int foo(X1 *p1, X2 *p2)
{
 p1->x1 = 0;
 p2->x2 = 1;
 return p1->x1;
}

In article <1iw4EvAinxp2Ewdn@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> In article <785ck9$qlu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
> writes
> >If I have two (non-layout compatible) POD structs
> >
> >struct X1 { /* ... */ int x1; /* ... */ };
> >struct X2 { /* ... */ int x2; /* ... */ };
> >
> >And two pointers
> >
> >X1 *p1;
> >X2 *p2;
> >
> >I would like to be able to assume that p1->x1 does not alias p2->x2, but I
> >cant justify that based on the above quote.
>
> But I think you are misconstruing the meaning of the quote.  What it
> says is that anything other than those things in the list will result in
> undefined behaviour, it does NOT say that doing the things in the list
> will work.

Exactly. So the question is this: Is my example on the list or not? As I read
it, it is on the list, (tho I wish It wasnt), and so foo() _could_ return 1.

>
> However how is your program going to provide such aliased access?  Only,
> as far as I can see, via some monstrous piece of coding such as:
>
> X1 x1, *p1 = &x1;
> X2 *p2 = (X1 *)(void *)p1;
>
> >
> >The problem I am seeing is that p2->x2 is an lvalue of type int. The object
> >pointed to by p1 is an aggregate which contains an int, so p2->x2 is
explictly
> >allowed to access the stored value of the object pointed to by p1...
>
> No, I do not think it is explcitly allowed to unless you have already
> introduced undefined behaviour in some other way.


>
> >
> >Im hoping that Im not reading it correctly, or that there is something
> >elsewhere in the standard which does make the assumption valid.
>
> Write some well-formed code that exhibits what you think is a problem.

If I could do that, I would know the answer question. Unfortunately an
inability to come up with a counter-example has never struck me as a good
proof that one doesnt exist.

> >
> >Im assuming that the assumption is good for non-POD.
> >
> >Im also aware that I could set p1 = (X1*)((char*)&p2->x2 - offsetof(X1, x1)).
> >The question is whether doing so invokes undefined/implementation defined
> >behaviour.
>
> If using a pointer that points to an object of the wrong type isn't
> undefined behaviour I think we might all just give up.

Im inclined to agree... but can you tell me how to read the standard in such a
way as to justify that remark?

Mark Williams

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: AllanW@my-dejanews.com
Date: 1999/01/22
Raw View
In article <1iw4EvAinxp2Ewdn@robinton.demon.co.uk>,
  Francis Glassborow <francisG@robinton.demon.co.uk> wrote:
> In article <785ck9$qlu$1@nnrp1.dejanews.com>, markw65@my-dejanews.com
> writes
> >If I have two (non-layout compatible) POD structs
> >
> >struct X1 { /* ... */ int x1; /* ... */ };
> >struct X2 { /* ... */ int x2; /* ... */ };
> >
> >And two pointers
> >
> >X1 *p1;
> >X2 *p2;
> >
> >I would like to be able to assume that p1->x1 does not alias p2->x2, but I
> >cant justify that based on the above quote.
>
> But I think you are misconstruing the meaning of the quote.  What it
> says is that anything other than those things in the list will result in
> undefined behaviour, it does NOT say that doing the things in the list
> will work.
>
> However how is your program going to provide such aliased access?  Only,
> as far as I can see, via some monstrous piece of coding such as:
>
> X1 x1, *p1 = &x1;
> X2 *p2 = (X1 *)(void *)p1;

In legacy C code, idioms such as this are common:
    struct rec_head {
        unsigned long cust_no;
        unsigned char rec_type;
        unsigned char fill[120];
    };
    struct rec_id {
        unsigned long cust_no;
        unsigned char rec_type; // 0
        unsigned char name[32], addr[32], city[32], state[3], zip[10];
        unsigned char fill[11];
    }
    struct rec_totals {
        unsigned long cust_no;
        unsigned char rec_type; // 1
        unsigned char fill[3];
        unsigned long balance;       // In pennies
        unsigned long cred_limit;    // In pennies
        unsigned long last_pay_amt;  // In pennies
        unsigned long last_pay_date;
        // ... etc ...
   };

Yes, a union could have been used, but wasn't. Yes, these are
generally layout-compatible for data elements that are shared,
but not always -- and sometimes code is buggy. For instance,
I worked on code that updated the balance even when the
rec_type was 0 -- and ended up changing the customer name.

----
AllanW@my-dejanews.com is a "Spam Magnet" -- never read.
Please reply in USENET only, sorry.

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/       Search, Read, Discuss, or Start Your Own


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: scott douglass <sdouglass%_%junk@_.arm.com>
Date: 1999/01/22
Raw View
markw65@my-dejanews.com wrote:
> So I repeat the question: Is there a conforming program such that the
> assumption is invalid. Im thinking along the lines of bizarre unions etc
> where x1 & x2 have managed to land on top of each other.
>
> ie can I assume the following function returns 0?
>
> int foo(X1 *p1, X2 *p2)
> {
>  p1->x1 = 0;
>  p2->x2 = 1;
>  return p1->x1;
> }

Is this the bizarre union example you wanted (or didn't want)?

struct X1 { int x1; };
struct X1a { char a2[4]; X1 x1a; };
struct X2 { char a2[4]; int x2; /* ... */ };
union U { X1a u1; X2 u2; };

// for some compilers offsetof(U, u1.x1a.x1) == offsetof(U, u2.x2)

int f() { U u; return foo(&u.u1.x1a, &u.u2); }

I guess my interpretation is that the aliasing is legal and the optimization is
not.  Too bad, I wish it was the other way.


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]