Topic: reinterpret_cast to extract bits


Author: Usenet@aristeia.com (Scott Meyers)
Date: Sat, 3 Jul 2004 00:03:28 +0000 (UTC)
Raw View
On Sat, 5 Jun 2004 07:54:44 +0000 (UTC), Gabriel Dos Reis wrote:
> No: You can access any object as a sequence of unsigned char.  That is
> explicitly exempted from the non-aliasing rule.

Color me ignorant, but what (non-)aliasing rule are we talking about?

Thanks,

Scott

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 3 Jul 2004 02:17:02 +0000 (UTC)
Raw View
Usenet@aristeia.com (Scott Meyers) writes:

| On Sat, 5 Jun 2004 07:54:44 +0000 (UTC), Gabriel Dos Reis wrote:
| > No: You can access any object as a sequence of unsigned char.  That is
| > explicitly exempted from the non-aliasing rule.
|
| Color me ignorant, but what (non-)aliasing rule are we talking about?

This is the rule 3.10/15:

  If 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 subaggregate 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.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Tue, 22 Jun 2004 17:39:43 +0000 (UTC)
Raw View
pdimov@gmail.com (Peter Dimov) writes:

| gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3hdtbm4hj.fsf@merlin.cs.tamu.edu>...
| > pdimov@gmail.com (Peter Dimov) writes:
| >
| > | gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
| > | > pdimov@gmail.com (Peter Dimov) writes:
| > | >
| > | > | I think that given
| > | > |
| > | > |   unsigned long to_ieee754_rep(float f);
| > | > |   float from_ieee754_rep(unsigned long l);
| > | >
| > | > And precisely how do I get those?
| > |
| > | How do you get std::vector? How do you get std::printf?
| >
| > As much as I hate "quote by authority", here is what I think you're
| > missing:
| >
| >    C was designed with the principle that you should be able to write
| >    its standard library in the language itself. That same principle
| >    guided the design of C++.
| >        -- Bjarne Stroustrup
| >
| >
| > It is very fashionable these days to put nearly every small thing as a
| > "magic" in the language or in the library.  Such a approach may
| > probably work in small but it fails to scale and to display sufficient
| > understanding.
|
| The functions aren't magic. They are implementable in the language.

If they're implementable in the language, I want to see how it could
be written and decide whether I whether there isn't any local
patch to a instance of a general problem.  Remember, this subthread
started because it was claimed that I don't need to have access to
the storage  bytes.

| They cannot be _portably_ implemented by the user, however, which is
| exactly why they belong to the standard library.

But, none of the solutions you suggest below is not portable.

| > Next time I need to send an integer over network in
| > network-order, I would ask to another magic function?
|
| No, because you don't need one. You can already obtain the value bits
| of an integer.
|
| > The "one possibility" is really trumping:  you need at least a pair of
| > functions for each floating point datatype.  Which gets you to 6
| > functions; and actually that count is far too optimistic, because in
| > case of multi-word floating-point datatypes (e.g. double, long double,
| > ..), you also need to know which words contain the sign, the exponent
| > and in which order; i.e. you're pretty much back to byte-ordering.
|
| For double, I need either
|
|   uint64_least_t to_ieee_rep( double v );

But this is not portable, which was your previous argument!

| or
|
|   pair<unsigned long, unsigned long> to_ieee_rep( double v );
|
| if 64 bit integers aren't available. Neither of these require any byte
| ordering, because I know which word is which; the whole point of

But, the pair above does not tell me where the sign bit is, the
exponent and mantissa go.  Those are the information I need.

| to_ieee_rep is to take care of the ordering issues for me.

No, it does not.  It does not give me the information I need: it does
not tell me which word contains the sign bit, the mantissa and the
exponent.  Without those, it is a nice but useless function.

Next, is long double -- whose implementation varies from 80 bits to
128 bits.  Now, you have to handle non-IEEE too (I gave IEEE as a
starting example, because it is easy enough, but as far as I can see,
it not solved by your functions.)

| Of course if the language or the library give me the tools I need to
| implement to_ieee_rep myself instead, that'd be good enough, too. My

It is not really the satisfaction of implementing to_ieee_rep myself
that I'm seeking, but the general meachanism that makes it possible,
because the byte-ordering is a general mechanism useful in other
system programming contexts.

| point here is that I've never needed these tools _except_ for that one
| function (or its general equivalent).

but they don't work.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Thu, 24 Jun 2004 15:48:09 +0000 (UTC)
Raw View
kuyper@wizard.net (James Kuyper) writes:

| gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3hdtbm4hj.fsf@merlin.cs.tamu.edu>...
| > pdimov@gmail.com (Peter Dimov) writes:
| >
| > | gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
| > | > pdimov@gmail.com (Peter Dimov) writes:
| > | >
| > | > | I think that given
| > | > |
| > | > |   unsigned long to_ieee754_rep(float f);
| > | > |   float from_ieee754_rep(unsigned long l);
| > | >
| > | > And precisely how do I get those?
| > |
| > | How do you get std::vector? How do you get std::printf?
| >
| > As much as I hate "quote by authority", here is what I think you're
| > missing:
| >
| >    C was designed with the principle that you should be able to write
| >    its standard library in the language itself. That same principle
| >    guided the design of C++.
| >        -- Bjarne Stroustrup
|
| Many of the things that were put into the C standard library were put
| there precisely because they could not be written in portable C.

There is a huge difference between being written in C and being
written in portable C.  Only very few, trivial programs could be
written in portable C.

| The
| best example is offsetof(); the typical expansion of the offsetof()
| macro is code that would, if it were user written code, have behavior
| that is either implementation-defined or undefined by the standard.

I mostly see offsetof() as poorman pointer-to-members -- and I would
really like to see their full expressions restored, i.e. complete them
so that they could be composed.

| The C language alone provides no methods of accessing any hardware;

Which is why people don't use C to program their hardware. <g>

| the stdio and signal libraries usually invoke OS-specific functions
| that are often themselves written in assembler.

Assembler is not excluded from C++.

| > | How do you get operator+(float, float)? I don't understand your question.
| >
| > See above.
|
| Like Peter, I still don't understand your question. He's not
| suggesting compiler magic of any kind, just some new standard library
| functions.

He does: My specific question was how I could implement those standard
library functions.  He replied along the line of how I do get
operator+(float, float).  Which suggests that there would be a magic
going one.  If there is no magic, then why not making the general
mechanism available to me, user?

(Now, you see you care more about abstract impossibilities, why do you
believe Peter's suggested functions do have any meaning on all
architectures?  First, I don't think they make any sense on a PowerPC)


| > | > | it should be possible to portably implement the IEEE-754 operations in
| > | > | software, regardless of the actual 'float' storage.
| > | >
| > | > I'm pretty sure given a large enough set of magic primitives, nearly
| > | > everything can be done -- just pretend they are given.
| > |
| > | Indeed, and the question is what is the minimal but complete set of
| > | primitives that enable us to implement that "nearly everything".
| >
| > I've tried many times, and have concluded that word-ordering,
| > byte-ordering and bit-ordering give a minimal, complete, nearly
| > perfect answer.  I've repeatedly asked for concrete examples from
| > those who pretend otherwise, yet I only get rhetorics back.
|
| The standard allows the bits and bytes within a multi-word integer to
| be completely and arbitrarily scrambled.

I'm well aware of that, thanks.  The point precisely is that no
matter how arbritrarily scrambled those ordering are _theoretically_
permitted, it is *finitely descriptible* and in *pratice*, there are
only very few varitions.  As a concrete point of eveidence, GCC, as
far as I know, is one of the compilers that covers as wide a range of
targets; still, I don't see there a zillion of byte-orderings.

| For instance, with two-byte
| words and 8-bit bytes, a four byte integer could be respresented by
| bits in the following order:
|
| byte   bits
| 0      0 7  8 15 16 23 24 31
| 1      1 6  9 14 17 22 25 30
| 2      2 5 10 13 18 21 26 29
| 3      3 4 11 12 19 20 27 28
|
| For such a representation, the concepts of "word order" and "byte
| order" would be essentially meaningless.

No, they are not, or they would not be, meaningless.  They are just
general mappings, that do not happen to be fictionary.

| I don't think anyone uses such represntations;

Yes, I forgot we're on comp.std.c++.  But even then, I see the
fiction above as pure distraction from the real core problem.
Because, we're talking about real programs running on real machines.

| I can't think of any good reason why they would;
| but it would be legal. Floating point representations are similarly
| unconstrained.

Yet, finitely desciptible.  And in real programs on real machine, even
more easily so.

| Are you suggesting that the standard should implicitly
| require that "word order" and "byte order" be meaningful concepts for
| all arithmetic types? I wouldn't object - I doubt that any real-world
| code would be affected.

I don't want the standard to contraint things in a way that would prevent
distractors from entertaining us with imaginaries stupidities.
However, I would like to see the standard describe byte-ordering and
word-ordering and make them effective on plateforms where they're
existant.  I.e., for virtually all practical cases.
I wuld hate to see local patches applied in isolation to small
instances of much more general concern (description of bit-ordering,
byte-ordering and word-ordering).


--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@gmail.com (Peter Dimov)
Date: Thu, 17 Jun 2004 15:45:13 +0000 (UTC)
Raw View
gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
> pdimov@gmail.com (Peter Dimov) writes:
>
> | I think that given
> |
> |   unsigned long to_ieee754_rep(float f);
> |   float from_ieee754_rep(unsigned long l);
>
> And precisely how do I get those?

How do you get std::vector? How do you get std::printf? How do you get
operator+(float, float)? I don't understand your question.

> | it should be possible to portably implement the IEEE-754 operations in
> | software, regardless of the actual 'float' storage.
>
> I'm pretty sure given a large enough set of magic primitives, nearly
> everything can be done -- just pretend they are given.

Indeed, and the question is what is the minimal but complete set of
primitives that enable us to implement that "nearly everything". One
possibility are the two functions above (or their equivalent). The
other possibility is your yet-unspecified set of storage query
primitives.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 19 Jun 2004 21:29:45 +0000 (UTC)
Raw View
pdimov@gmail.com (Peter Dimov) writes:

| gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
| > pdimov@gmail.com (Peter Dimov) writes:
| >
| > | I think that given
| > |
| > |   unsigned long to_ieee754_rep(float f);
| > |   float from_ieee754_rep(unsigned long l);
| >
| > And precisely how do I get those?
|
| How do you get std::vector? How do you get std::printf?

As much as I hate "quote by authority", here is what I think you're
missing:

   C was designed with the principle that you should be able to write
   its standard library in the language itself. That same principle
   guided the design of C++.
       -- Bjarne Stroustrup


It is very fashionable these days to put nearly every small thing as a
"magic" in the language or in the library.  Such a approach may
probably work in small but it fails to scale and to display sufficient
understanding.  Next time I need to send an integer over network in
network-order, I would ask to another magic function?  That definitely
looks to me a slippery slope.

| How do you get operator+(float, float)? I don't understand your question.

See above.

| > | it should be possible to portably implement the IEEE-754 operations in
| > | software, regardless of the actual 'float' storage.
| >
| > I'm pretty sure given a large enough set of magic primitives, nearly
| > everything can be done -- just pretend they are given.
|
| Indeed, and the question is what is the minimal but complete set of
| primitives that enable us to implement that "nearly everything".

I've tried many times, and have concluded that word-ordering,
byte-ordering and bit-ordering give a minimal, complete, nearly
perfect answer.  I've repeatedly asked for concrete examples from
those who pretend otherwise, yet I only get rhetorics back.

| One
| possibility are the two functions above (or their equivalent). The
| other possibility is your yet-unspecified set of storage query
| primitives.

The "one possibility" is really trumping:  you need at least a pair of
functions for each floating point datatype.  Which gets you to 6
functions; and actually that count is far too optimistic, because in
case of multi-word floating-point datatypes (e.g. double, long double,
..), you also need to know which words contain the sign, the exponent
and in which order; i.e. you're pretty much back to byte-ordering.
I would suggest that you try on several different architectures.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Mon, 21 Jun 2004 16:59:15 +0000 (UTC)
Raw View
gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3hdtbm4hj.fsf@merlin.cs.tamu.edu>...
> pdimov@gmail.com (Peter Dimov) writes:
>
> | gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
> | > pdimov@gmail.com (Peter Dimov) writes:
> | >
> | > | I think that given
> | > |
> | > |   unsigned long to_ieee754_rep(float f);
> | > |   float from_ieee754_rep(unsigned long l);
> | >
> | > And precisely how do I get those?
> |
> | How do you get std::vector? How do you get std::printf?
>
> As much as I hate "quote by authority", here is what I think you're
> missing:
>
>    C was designed with the principle that you should be able to write
>    its standard library in the language itself. That same principle
>    guided the design of C++.
>        -- Bjarne Stroustrup

Many of the things that were put into the C standard library were put
there precisely because they could not be written in portable C. The
best example is offsetof(); the typical expansion of the offsetof()
macro is code that would, if it were user written code, have behavior
that is either implementation-defined or undefined by the standard.
The C language alone provides no methods of accessing any hardware;
the stdio and signal libraries usually invoke OS-specific functions
that are often themselves written in assembler.

> | How do you get operator+(float, float)? I don't understand your question.
>
> See above.

Like Peter, I still don't understand your question. He's not
suggesting compiler magic of any kind, just some new standard library
functions.


> | > | it should be possible to portably implement the IEEE-754 operations in
> | > | software, regardless of the actual 'float' storage.
> | >
> | > I'm pretty sure given a large enough set of magic primitives, nearly
> | > everything can be done -- just pretend they are given.
> |
> | Indeed, and the question is what is the minimal but complete set of
> | primitives that enable us to implement that "nearly everything".
>
> I've tried many times, and have concluded that word-ordering,
> byte-ordering and bit-ordering give a minimal, complete, nearly
> perfect answer.  I've repeatedly asked for concrete examples from
> those who pretend otherwise, yet I only get rhetorics back.

The standard allows the bits and bytes within a multi-word integer to
be completely and arbitrarily scrambled. For instance, with two-byte
words and 8-bit bytes, a four byte integer could be respresented by
bits in the following order:

byte   bits
0      0 7  8 15 16 23 24 31
1      1 6  9 14 17 22 25 30
2      2 5 10 13 18 21 26 29
3      3 4 11 12 19 20 27 28

For such a representation, the concepts of "word order" and "byte
order" would be essentially meaningless. I don't think anyone uses
such represntations; I can't think of any good reason why they would;
but it would be legal. Floating point representations are similarly
unconstrained. Are you suggesting that the standard should implicitly
require that "word order" and "byte order" be meaningful concepts for
all arithmetic types? I wouldn't object - I doubt that any real-world
code would be affected.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@gmail.com (Peter Dimov)
Date: Mon, 21 Jun 2004 16:59:27 +0000 (UTC)
Raw View
gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3hdtbm4hj.fsf@merlin.cs.tamu.edu>...
> pdimov@gmail.com (Peter Dimov) writes:
>
> | gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3k6yamoew.fsf@merlin.cs.tamu.edu>...
> | > pdimov@gmail.com (Peter Dimov) writes:
> | >
> | > | I think that given
> | > |
> | > |   unsigned long to_ieee754_rep(float f);
> | > |   float from_ieee754_rep(unsigned long l);
> | >
> | > And precisely how do I get those?
> |
> | How do you get std::vector? How do you get std::printf?
>
> As much as I hate "quote by authority", here is what I think you're
> missing:
>
>    C was designed with the principle that you should be able to write
>    its standard library in the language itself. That same principle
>    guided the design of C++.
>        -- Bjarne Stroustrup
>
>
> It is very fashionable these days to put nearly every small thing as a
> "magic" in the language or in the library.  Such a approach may
> probably work in small but it fails to scale and to display sufficient
> understanding.

The functions aren't magic. They are implementable in the language.
They cannot be _portably_ implemented by the user, however, which is
exactly why they belong to the standard library.

> Next time I need to send an integer over network in
> network-order, I would ask to another magic function?

No, because you don't need one. You can already obtain the value bits
of an integer.

> The "one possibility" is really trumping:  you need at least a pair of
> functions for each floating point datatype.  Which gets you to 6
> functions; and actually that count is far too optimistic, because in
> case of multi-word floating-point datatypes (e.g. double, long double,
> ..), you also need to know which words contain the sign, the exponent
> and in which order; i.e. you're pretty much back to byte-ordering.

For double, I need either

  uint64_least_t to_ieee_rep( double v );

or

  pair<unsigned long, unsigned long> to_ieee_rep( double v );

if 64 bit integers aren't available. Neither of these require any byte
ordering, because I know which word is which; the whole point of
to_ieee_rep is to take care of the ordering issues for me.

Of course if the language or the library give me the tools I need to
implement to_ieee_rep myself instead, that'd be good enough, too. My
point here is that I've never needed these tools _except_ for that one
function (or its general equivalent).

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@gmail.com (Peter Dimov)
Date: Tue, 15 Jun 2004 18:00:45 +0000 (UTC)
Raw View
gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3r7smnabk.fsf@merlin.cs.tamu.edu>...
> pdimov@mmltd.net (Peter Dimov) writes:
>
> | I don't agree. The real issue is that value bits and storage bits are
> | different things, and we are typically interested in the former. It is
>
> Our experience obviously don't match.  In various attempt to implement
> IEEE-754 floating poing functions in sofwate, I've found that that I
> need often have need to know about the storage bits than the value
> bits.

I may be missing something, and I'm not an FP expert by any stretch of
the imagination, but the IEEE-754 standard doesn't seem to mention
storage bits. It only defines value bits.

I think that given

  unsigned long to_ieee754_rep(float f);
  float from_ieee754_rep(unsigned long l);

it should be possible to portably implement the IEEE-754 operations in
software, regardless of the actual 'float' storage.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Wed, 16 Jun 2004 15:40:21 +0000 (UTC)
Raw View
pdimov@gmail.com (Peter Dimov) writes:

| gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m3r7smnabk.fsf@merlin.cs.tamu.edu>...
| > pdimov@mmltd.net (Peter Dimov) writes:
| >
| > | I don't agree. The real issue is that value bits and storage bits are
| > | different things, and we are typically interested in the former. It is
| >
| > Our experience obviously don't match.  In various attempt to implement
| > IEEE-754 floating poing functions in sofwate, I've found that that I
| > need often have need to know about the storage bits than the value
| > bits.
|
| I may be missing something, and I'm not an FP expert by any stretch of
| the imagination, but the IEEE-754 standard doesn't seem to mention
| storage bits.

Yes, just like the C++ standard does not mention storage files.  Yet,
they ought to be implemented one way of the other.  The IEEE-754
specification gives an abstract model.  That abstract model is to
be mapped to implementation. At some point, the abstractions need to
be concretized -- which is what I was referring to when I was saying
"In various attempt to implement ....".

| It only defines value bits.
|
| I think that given
|
|   unsigned long to_ieee754_rep(float f);
|   float from_ieee754_rep(unsigned long l);

And precisely how do I get those?

| it should be possible to portably implement the IEEE-754 operations in
| software, regardless of the actual 'float' storage.

I'm pretty sure given a large enough set of magic primitives, nearly
everything can be done -- just pretend they are given.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 12 Jun 2004 18:19:04 +0000 (UTC)
Raw View
pdimov@mmltd.net (Peter Dimov) writes:

| gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m33c547owc.fsf@merlin.cs.tamu.edu>...
| > noway@sorry.com ("Giovanni Bajo") writes:
| >
| > | There is no way to do this in a byte-order independent way, since the only way
| > | to get access to the bits in the first place is to use unsigned char*.
| > |
| > | This is exactly why I started this thread, and I am proposing the following
| > | extension to C++:
| >
| > The real issue as I see it is to define the notion of byte-ordering
| > (and alignment and other primitives).  Local patches that extend the
| > definition domain of reinterpret_cast<> as you suggested aren't good
| > solution.
|
| I don't agree. The real issue is that value bits and storage bits are
| different things, and we are typically interested in the former. It is

Our experience obviously don't match.  In various attempt to implement
IEEE-754 floating poing functions in sofwate, I've found that that I
need often have need to know about the storage bits than the value
bits.

| true that if I am given a storage bit to value bit mapping, or the

byte-ordering gives you that mapping.

| information that is necessary to construct such a mapping, then I can
| access the storage as an array of unsigned chars and extract the value
| bits.

Exactly.

| But this seems a fairly convoluted way to solve the simple
| problem of obtaining the value bits.

Convoluted is in the eye of the beholder.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Sun, 13 Jun 2004 04:19:04 +0000 (UTC)
Raw View
Gabriel Dos Reis wrote:

>> I don't agree. The real issue is that value bits and storage bits are
>> different things, and we are typically interested in the former. It is

>Our experience obviously don't match.  In various attempt to implement
>IEEE-754 floating poing functions in sofwate I've found that that I
>need often have need to know about the storage bits than the value
>bits.

In my experience, the only thing I ever wanted is the value bits. I can't care
less how they are stored in memory, as long as I can access the mantissa, the
sign or the exponent correctly.

> Convoluted is in the eye of the beholder.

I beg to disagree. Using unsigned char* to access float is non-trivial, hard to
teach ("why can't I just use int* like everybody does?"), and does not hide the
value vs storage issue. I strongly think C++ could benefit from a short,
compact way to access (a copy of) the value bits. reinterpret_cast is my
suggestion, but a standard function "long f2l(float);" could also work. I think
that using a standard function creates a false belief that the result is not
implementation-defined, while the cast makes it more explicit. Also, the
reinterpret_cast is just a way to write *(unsigned long*)&f but without
breaking aliasing rules, so it is easy to teach and understand as it matches
existing practice.
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Mon, 14 Jun 2004 16:16:04 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

| Gabriel Dos Reis wrote:
|
| >> I don't agree. The real issue is that value bits and storage bits are
| >> different things, and we are typically interested in the former. It is
|
| >Our experience obviously don't match.  In various attempt to implement
| >IEEE-754 floating poing functions in sofwate I've found that that I
| >need often have need to know about the storage bits than the value
| >bits.
|
| In my experience, the only thing I ever wanted is the value bits. I
| can't care less how they are stored in memory, as long as I can
| access the mantissa, the sign or the exponent correctly.

Do you have a working implementation of the extended IEEE-754
functions on a couple of different architectures I can look at?
For example, IEEE-754 abs() is truly non-arithmetic (despite popular
belief) and its correct implementation requires more than just reading
a sign bit: It requires setting it too.

| > Convoluted is in the eye of the beholder.
|
| I beg to disagree. Using unsigned char* to access float is
| non-trivial,

It is probably non-trivial the first time one sees it.  Using unsigned
char* to access object representation is documented and well
understood for more than 2 decades now.

| hard to
| teach ("why can't I just use int* like everybody does?"),

Who is "everybody".  First you need to explain me under what
circumstances I would need to do that, and second why you would teach
that and to whom.  Once, you have defined the audience, I believe it
will becomes clear what could be qualified hard or unteachable.

| and does not hide the
| value vs storage issue. I strongly think C++ could benefit from a short,
| compact way to access (a copy of) the value bits. reinterpret_cast is my
| suggestion, but a standard function "long f2l(float);" could also work. I think
| that using a standard function creates a false belief that the result is not
| implementation-defined,

Then you're profondly mistaken about standard function, and extending
the definition domain reinterpret_cast<> would just aggrave your
misunderstanding.  I have met many instances of the belief (in various
programming language communities) that if something is expressed by a
keyword then it is very efficient, if it is expressed as a function
then it must be inefficient.  This is the first time I meet the
variant you write above.  Do you really believe that the result of
numeric_limits<T>::max() is not implementation defined?  Or that the result
of

   std::ifstream toto("titi.dat");

is not implementation-defined?

I see your hypotethical belief to be either a good reason not to go
down the road of reinterpret_cast<> or a bad reason to have it.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: pdimov@mmltd.net (Peter Dimov)
Date: Fri, 11 Jun 2004 20:36:19 +0000 (UTC)
Raw View
gdr@cs.tamu.edu (Gabriel Dos Reis) wrote in message news:<m33c547owc.fsf@merlin.cs.tamu.edu>...
> noway@sorry.com ("Giovanni Bajo") writes:
>
> | There is no way to do this in a byte-order independent way, since the only way
> | to get access to the bits in the first place is to use unsigned char*.
> |
> | This is exactly why I started this thread, and I am proposing the following
> | extension to C++:
>
> The real issue as I see it is to define the notion of byte-ordering
> (and alignment and other primitives).  Local patches that extend the
> definition domain of reinterpret_cast<> as you suggested aren't good
> solution.

I don't agree. The real issue is that value bits and storage bits are
different things, and we are typically interested in the former. It is
true that if I am given a storage bit to value bit mapping, or the
information that is necessary to construct such a mapping, then I can
access the storage as an array of unsigned chars and extract the value
bits. But this seems a fairly convoluted way to solve the simple
problem of obtaining the value bits.

Of course the mechanism that gives me the value bits of a float need
not be reinterpret_cast; a function will do just as well. I could also
use a function that gives me the value bits of the IEEE representation
of that float. :-)

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: osv@javad.ru (Sergei Organov)
Date: Wed, 9 Jun 2004 17:05:58 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

> Sergei Organov wrote:
>
> > // Serialize 32-bit IEEE floating point LSB first no matter what
> > // bytes order CPU uses.
> > void out_float(float f) {
> >   // ??? How to do it without invoking undefined behavior ???
> >   //
> >   //   -- UB due to aliasing rules
> >   //   out_uint(*(unsigned int*)&f);
> >   //
> >   //   -- UB due to union access rules
> >   //   union { unsigned int u; float f; } u;
> >   //   u.f = f; out_uint(u.u);
> >   //
> >   //   -- UB??? If so, why? If not, too ugly trick anyway.
> >   //   struct S { unsigned int u; float f; };
> >   //   out_uint(((S*)&f)->u);
> > }
>
> There is no way to do this in a byte-order independent way, since the
> only way to get access to the bits in the first place is to use
> unsigned char*.

Are you sure? What does the following mean:

"If 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
  undefined:

  --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),

  ...
"

Does my last implementation of out_float() invoke undefined behavior
then?

--
Sergei.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: david.thompson1@worldnet.att.net (Dave Thompson)
Date: Thu, 10 Jun 2004 17:43:47 +0000 (UTC)
Raw View
On Wed, 2 Jun 2004 20:28:46 +0000 (UTC), kuyper@wizard.net (James
Kuyper) wrote:

> david.thompson1@worldnet.att.net (Dave Thompson) wrote in message news:<0grnb0djk1e7dd8llriurc3eg2bec4t2fs@4ax.com>...
<snip>
> > The parentheses on each term aren't needed in either case; either <<
> > or * has higher precedence than |, and * is also above +.
>
> The parentheses are needed when using shift operators. <snip>

OK, I elided too much. Parens are needed for << with +, yes. They are
not needed for << with |, which I consider a more sensible combination
(both bitwise); nor for * with + (arithmetic) or * with | (mixed).

- David.Thompson1 at worldnet.att.net

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Thu, 10 Jun 2004 17:44:48 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

| There is no way to do this in a byte-order independent way, since the only way
| to get access to the bits in the first place is to use unsigned char*.
|
| This is exactly why I started this thread, and I am proposing the following
| extension to C++:

The real issue as I see it is to define the notion of byte-ordering
(and alignment and other primitives).  Local patches that extend the
definition domain of reinterpret_cast<> as you suggested aren't good
solution.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Mon, 7 Jun 2004 16:47:36 +0000 (UTC)
Raw View
osv@javad.ru (Sergei Organov) wrote in message news:<1086331990.187455@ns.topconrd.ru>...
> kuyper@wizard.net (James Kuyper) writes:
> > noway@sorry.com ("Giovanni Bajo") wrote:
> > > So now things get trickier. I know my implementation has "float" as
> > > a 4 byte IEEE quantity, layed out in memory as little-endian. I want
> > > to access those 4 bytes (those 32bits) as they were an integer, to
> > > play with its bits. Is there *any* way to do this in C++ in a way
> > > that does not yield undefined behaviour (but just an implementation
> > > defined result)?
> >
> > unsigned long float_bits(float f)
> > {
> >     unsigned char* bytes=(unsigned char*)&f;
> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> > }

It's embarrassing enough to have made that mistake once; seeing it
repeated in every responsie is worse. :-( Here's a correction that
incorporates all of the relevant criticisms so far:

        return ((unsigned long)bytes[0]<<3*CHAR_BIT) +
                 (unsigned long)bytes[1]<<2*CHAR_BIT) +
                 (unsigned long)bytes[2]<<CHAR_BIT) + bytes[3];

> > If you know that 'int' is 32 bits on that platform, you can use
> > unsigned int rather than unsigned long.
>
> Such solution has a drawback: it assumes particular byte order on
> the target. Besides union trick, there is another solution that

Trace back the thread: The question I was responding to specified the
byte order. It also specified 32 bits and 4 bytes, which means that
using CHAR_BIT was unnecessary. I used CHAR_BIT because the cost of
removing the assumption of 8-bit bytes was cheap. The cost of covering
all possible byte orderings is much higher.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Mon, 7 Jun 2004 16:47:43 +0000 (UTC)
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) wrote in message news:<h44XQBoPtEwAFwc6@robinton.demon.co.uk>...
> In article <8b42afac.0406031350.4dd3f5a8@posting.google.com>, James
> Kuyper <kuyper@wizard.net> writes
> >noway@sorry.com ("Giovanni Bajo") wrote in message news:<09vvc.34206$Wc.1158868@twister2.libero.it>...
> >> James Kuyper wrote:
> >>
> >> > unsigned long float_bits(float f)
> >> > {
> >> >     unsigned char* bytes=(unsigned char*)&f;
> >> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> >> > }
> >>
> >> Doesn't this totally break aliasing rules and thus yields undefined behaviour?
> >
> >Could you cite the exact section number or text of the rule you think it violates?
>
> It assumes that sizeof(float) >= 4. There is no such requirement in the
> Standard. sizeof(float) is only required to be greater than zero.

There was, however, such a requirement in the problem specification
that this code was meant to be a solution for. On a platform that
matches the problem specification, what rule does this violate?
Of course, it doesn't work; please refer to the corrected version I've
posted on another branch of this discussion.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: osv@javad.ru (Sergei Organov)
Date: Tue, 8 Jun 2004 17:57:35 +0000 (UTC)
Raw View
kuyper@wizard.net (James Kuyper) writes:
> osv@javad.ru (Sergei Organov) wrote:
[...]
> > Such solution has a drawback: it assumes particular byte order on
> > the target. Besides union trick, there is another solution that
>
> Trace back the thread: The question I was responding to specified the
> byte order.

I didn't say proposed solution doesn't solve the problem described in
the message you've replied to. I.e., it was not a critique of your
solution.

What I'm trying to say is that initial union trick (if it were allowed
by the standard) would solve wider range of problems. For example, there
is a way to serialize a 32-bit integer into a stream of bytes having
particular bytes order that will work on both big- and little-endian
CPUs, but it doesn't seem to be a way to do the same with 32-bit IEEE
floating point without invoking undefined behavior:

void out(unsigned char c) { ... }

// Serialize 32-bit integer LSB first no matter what bytes order CPU
// uses.
void out_uint(unsigned int u) {
  out(u); out(u >> 8); out(u >> 16); out(u >> 24);
}

// Serialize 32-bit IEEE floating point LSB first no matter what
// bytes order CPU uses.
void out_float(float f) {
  // ??? How to do it without invoking undefined behavior ???
  //
  //   -- UB due to aliasing rules
  //   out_uint(*(unsigned int*)&f);
  //
  //   -- UB due to union access rules
  //   union { unsigned int u; float f; } u;
  //   u.f = f; out_uint(u.u);
  //
  //   -- UB??? If so, why? If not, too ugly trick anyway.
  //   struct S { unsigned int u; float f; };
  //   out_uint(((S*)&f)->u);
}


--
Sergei.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Wed, 9 Jun 2004 02:41:54 +0000 (UTC)
Raw View
Sergei Organov wrote:

> // Serialize 32-bit IEEE floating point LSB first no matter what
> // bytes order CPU uses.
> void out_float(float f) {
>   // ??? How to do it without invoking undefined behavior ???
>   //
>   //   -- UB due to aliasing rules
>   //   out_uint(*(unsigned int*)&f);
>   //
>   //   -- UB due to union access rules
>   //   union { unsigned int u; float f; } u;
>   //   u.f = f; out_uint(u.u);
>   //
>   //   -- UB??? If so, why? If not, too ugly trick anyway.
>   //   struct S { unsigned int u; float f; };
>   //   out_uint(((S*)&f)->u);
> }

There is no way to do this in a byte-order independent way, since the only way
to get access to the bits in the first place is to use unsigned char*.

This is exactly why I started this thread, and I am proposing the following
extension to C++:

void out_float(float f) {
    out_uint(reinterpret_cast<unsigned int>(f));
}

--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: francis@robinton.demon.co.uk (Francis Glassborow)
Date: Fri, 4 Jun 2004 16:08:44 +0000 (UTC)
Raw View
In article <8b42afac.0406031350.4dd3f5a8@posting.google.com>, James
Kuyper <kuyper@wizard.net> writes
>noway@sorry.com ("Giovanni Bajo") wrote in message news:<09vvc.34206$Wc.1158868@twister2.libero.it>...
>> James Kuyper wrote:
>>
>> > unsigned long float_bits(float f)
>> > {
>> >     unsigned char* bytes=(unsigned char*)&f;
>> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
>> > }
>>
>> Doesn't this totally break aliasing rules and thus yields undefined behaviour?
>
>Could you cite the exact section number or text of the rule you think it violates?

It assumes that sizeof(float) >= 4. There is no such requirement in the
Standard. sizeof(float) is only required to be greater than zero.

--
Francis Glassborow      ACCU
Author of 'You Can Do It!' see http://www.spellen.org/youcandoit
For project ideas and contributions: http://www.spellen.org/youcandoit/projects

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 5 Jun 2004 07:54:44 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

| James Kuyper wrote:
|
| > unsigned long float_bits(float f)
| > {
| >     unsigned char* bytes=(unsigned char*)&f;
| >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
| > }
|
| Doesn't this totally break aliasing rules and thus yields undefined behaviour?

No: You can access any object as a sequence of unsigned char.  That is
explicitly exempted from the non-aliasing rule.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 5 Jun 2004 07:54:55 +0000 (UTC)
Raw View
francis@robinton.demon.co.uk (Francis Glassborow) writes:

| In article <8b42afac.0406031350.4dd3f5a8@posting.google.com>, James
| Kuyper <kuyper@wizard.net> writes
| >noway@sorry.com ("Giovanni Bajo") wrote in message news:<09vvc.34206$Wc.1158868@twister2.libero.it>...
| >> James Kuyper wrote:
| >>
| >> > unsigned long float_bits(float f)
| >> > {
| >> >     unsigned char* bytes=(unsigned char*)&f;
| >> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
| >> > }
| >>
| >> Doesn't this totally break aliasing rules and thus yields undefined behaviour?
| >
| >Could you cite the exact section number or text of the rule you think it violates?
|
| It assumes that sizeof(float) >= 4.

Giovanni said in an earlier posting that that is part of the working
assumptions.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 5 Jun 2004 07:55:09 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

[...]

| What I was trying to ask with this thread is: can't we make the above just be
| "reinterpret_cast<unsigned long>(f)" ? I think this kind of extension to the
| standard is useful and does not break any existing well-formed program.

If defined, its meaning would be entirely depending on the
implementation, and it does not improve over anything -- it can be
done as currently with the standard.  I don't believe I would like to
see the definition domain of reinterpret_cast extended in that
direction.  In effect, I rather see that domain reduced.

Consider:

     template<class T, class U>
      inline T bytes_as(U& u)
      {
        return  reinterpret_cast<T&>(u);
      }

     template<class T, class U>
      inline T bytes_as(const U& u)
      {
        return  reinterpret_cast<const T&>(u);
      }

| It also
| prevents all the problems with integer promotions, casts, shifts, and the such.

With your working assumptions. try the above.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Sat, 5 Jun 2004 07:55:36 +0000 (UTC)
Raw View
osv@javad.ru (Sergei Organov) writes:

| Such solution has a drawback: it assumes particular byte order on
| the target.

That was part of the working assumptions made by Giovanni.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Sun, 6 Jun 2004 23:53:45 +0000 (UTC)
Raw View
Gabriel Dos Reis wrote:

>> What I was trying to ask with this thread is: can't we make the
>> above just be "reinterpret_cast<unsigned long>(f)" ? I think this
>> kind of extension to the standard is useful and does not break any
>> existing well-formed program.
>
> If defined, its meaning would be entirely depending on the
> implementation, and it does not improve over anything -- it can be
> done as currently with the standard.

Of course. But it took a few posts in comp.std.c++ to make everybody agree that
James' function was correct, that the shift did not need a cast, and so on. My
points:

- I think what I am trying to achieve is a valid, reasonable, real-world,
common goal.
- The solution by James requires a function to do the conversion (and I hope
compilers are smart enough to realize that they don't need to generate the
shifts and the ors), and another function to convert back from integer to
float.
- It is slightly harder to explain people that *(int*)&f is invalid, so they
should use *(unsigned char*)&f. Heck, I still keep getting this wrong even if I
know about the *existence* of aliasing rules in the first place.
- My proposed extension does not break any existing program
- My proposed extension is very easy to read and interpret for the users, and
makes immediatly clear what the code is trying to do. It is also easier to
teach, and to explain people to just avoid pointer tricks and use the
straightforward syntax.
- My proposed extension will probably work correctly on both big-endian and
little-endian machines, without the need of different functions.

Of course, this new semantic of reinterpret_cast<A>(b) would be well-formed
only if sizeof(A) == sizeof(typeof(b)), and with A and typeof(b) builtin types.

> I don't believe I would like to
> see the definition domain of reinterpret_cast extended in that
> direction.  In effect, I rather see that domain reduced.
>
> Consider:
>
>      template<class T, class U>
>       inline T bytes_as(U& u)
>       {
>         return  reinterpret_cast<T&>(u);
>       }
>
>      template<class T, class U>
>       inline T bytes_as(const U& u)
>       {
>         return  reinterpret_cast<const T&>(u);
>       }

Well, as far as I can see, this can only be called with bytes_as<char> or
bytes_as<unsigned char> without breaking the aliasing rules. So I'm not sure
how they help me. It looks like I still have to access bytes by bytes, and
recompose the value through shifts. Or am I missing something?
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Wed, 2 Jun 2004 20:28:46 +0000 (UTC)
Raw View
david.thompson1@worldnet.att.net (Dave Thompson) wrote in message news:<0grnb0djk1e7dd8llriurc3eg2bec4t2fs@4ax.com>...
> On Wed, 26 May 2004 14:21:59 +0000 (UTC),
> Michiel.Salters@logicacmg.com (Michiel Salters) wrote:
>
> > kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b@posting.google.com>...
> >
> > > unsigned long float_bits(float f)
> > > {
> > >     unsigned char* bytes=(unsigned char*)&f;
> > >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> > > }
> >
> > unsigned long float_bits(float f)
> > {
> >     unsigned char* bytes=(unsigned char*)&f;
> >     return (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];
>
> To be safe the first two must be cast to unsigned long (the default
> promotion is to int, which may be only 16 bits), and the third should
> be cast at least to unsigned int (the default signed int might not
> shift correctly, although usually it does).

Agreed. I was going to send out a self-correction to the shift
arguments, but Michael beat me to the punch, so I didn't bother. My
correction had the necessary casts that you refer to.

> ... Assuming CHAR_BIT==8, as
> is usual and without which this code obviously doesn't work at all.

Which can be addressed by using CHAR_BIT explicitly.

> The parentheses on each term aren't needed in either case; either <<
> or * has higher precedence than |, and * is also above +.

The parentheses are needed when using shift operators. The standard
isn't written in terms of operator precedence, but the grammar rules
it does use have the same effect for most of the operators (the
interaction of ?: with the other opreators can't be described purely
in terms of operator precedence). The relevant grammar rules for this
case are

5.7p1:
_additive-expression_:
             _multiplicative-expression_
             _additive_expression_ + _multiplicative-expression_

5.8p1:
_shift-expression_:
             _additive-expression_
              _shift-expression_ << _additive-expression_

Therefore, multiplication has a precedence higher than addition, but
the shift operator has a precedence that is lower than addition.
Therefore, the parentheses are necessary.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Thu, 3 Jun 2004 17:25:24 +0000 (UTC)
Raw View
James Kuyper wrote:

> unsigned long float_bits(float f)
> {
>     unsigned char* bytes=(unsigned char*)&f;
>     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> }

Doesn't this totally break aliasing rules and thus yields undefined behaviour?
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 3 Jun 2004 21:56:24 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") wrote in message news:<09vvc.34206$Wc.1158868@twister2.libero.it>...
> James Kuyper wrote:
>
> > unsigned long float_bits(float f)
> > {
> >     unsigned char* bytes=(unsigned char*)&f;
> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> > }
>
> Doesn't this totally break aliasing rules and thus yields undefined behaviour?

Could you cite the exact section number or text of the rule you think it violates?

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Fri, 4 Jun 2004 16:04:43 +0000 (UTC)
Raw View
James Kuyper wrote:

>>> unsigned long float_bits(float f)
>>> {
>>>     unsigned char* bytes=(unsigned char*)&f;
>>>     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
>>> }
>>
>> Doesn't this totally break aliasing rules and thus yields undefined
>> behaviour?
>
> Could you cite the exact section number or text of the rule you think
> it violates?

Sorry, I was thinking it was violating [basic.lval]/15, but I forgot that char
or unsigned char can alias everything. So you are right and the code is
obviously correct.

What I was trying to ask with this thread is: can't we make the above just be
"reinterpret_cast<unsigned long>(f)" ? I think this kind of extension to the
standard is useful and does not break any existing well-formed program. It also
prevents all the problems with integer promotions, casts, shifts, and the such.
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: osv@javad.ru (Sergei Organov)
Date: Fri, 4 Jun 2004 16:05:53 +0000 (UTC)
Raw View
kuyper@wizard.net (James Kuyper) writes:
> noway@sorry.com ("Giovanni Bajo") wrote:
> > So now things get trickier. I know my implementation has "float" as
> > a 4 byte IEEE quantity, layed out in memory as little-endian. I want
> > to access those 4 bytes (those 32bits) as they were an integer, to
> > play with its bits. Is there *any* way to do this in C++ in a way
> > that does not yield undefined behaviour (but just an implementation
> > defined result)?
>
> unsigned long float_bits(float f)
> {
>     unsigned char* bytes=(unsigned char*)&f;
>     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> }
>
> If you know that 'int' is 32 bits on that platform, you can use
> unsigned int rather than unsigned long.

Such solution has a drawback: it assumes particular byte order on
the target. Besides union trick, there is another solution that
only assumes bytes ordering is the same for floats and ints:

unsigned int float_bits(float f)
{
  return *(unsigned int*)&f;
}

but it's an undefined behavior as well, thanks aliasing rules. :(

The question I still don't have answer for is: does the following invoke
undefined behavior due to aliasing rules:

struct A {
  unsigned int res;
  float x;
};

unsigned int float_bits(float f)
{
  return ((A *)&f)->res;
}

From

 "If 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
  undefined:

  --the dynamic type of the object,
  ...
  --an  aggregate  or union type that includes one of the aforementioned
    types among its members..."

it seems that it's not an undefined behavior, as access is through an
aggregate (struct A) that includes 'x' member which type matches the
dynamic type 'float' of the 'f'.

Though I don't believe the intention is to allow such an ugly trick. Could
somebody clarify please?

--
Sergei.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Thu, 27 May 2004 21:11:04 +0000 (UTC)
Raw View
Michiel.Salters@logicacmg.com (Michiel Salters) wrote in message news:<fcaee77e.0405260232.307d0c2b@posting.google.com>...
> kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b@posting.google.com>...
>
> > unsigned long float_bits(float f)
> > {
> >     unsigned char* bytes=(unsigned char*)&f;
> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> > }
>
> unsigned long float_bits(float f)
> {
>     unsigned char* bytes=(unsigned char*)&f;
>     return (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];
> }

That's embarrassing! I orginally wrote the message using
multiplication by hexedecimal literals; when I rewrote it using
shifts, I counted hex digits instead of bits. Sorry.

Using | rather than + is a stylistic improvement, but I don't believe
it changes the results.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: david.thompson1@worldnet.att.net (Dave Thompson)
Date: Tue, 1 Jun 2004 17:06:02 +0000 (UTC)
Raw View
On Wed, 26 May 2004 14:21:59 +0000 (UTC),
Michiel.Salters@logicacmg.com (Michiel Salters) wrote:

> kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b@posting.google.com>...
>
> > unsigned long float_bits(float f)
> > {
> >     unsigned char* bytes=(unsigned char*)&f;
> >     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> > }
>
> unsigned long float_bits(float f)
> {
>     unsigned char* bytes=(unsigned char*)&f;
>     return (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];

To be safe the first two must be cast to unsigned long (the default
promotion is to int, which may be only 16 bits), and the third should
be cast at least to unsigned int (the default signed int might not
shift correctly, although usually it does). Assuming CHAR_BIT==8, as
is usual and without which this code obviously doesn't work at all.

Alternatively, use * 0x100U etc. and you don't need to cast because
the usual arithmetic conversions for binary operations do it for you,
and any half-decent compiler (on any plausible machine) will actually
produce shift instructions anyway.

The parentheses on each term aren't needed in either case; either <<
or * has higher precedence than |, and * is also above +.


- David.Thompson1 at worldnet.att.net

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: Michiel.Salters@logicacmg.com (Michiel Salters)
Date: Wed, 26 May 2004 14:21:59 +0000 (UTC)
Raw View
kuyper@wizard.net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b@posting.google.com>...

> unsigned long float_bits(float f)
> {
>     unsigned char* bytes=(unsigned char*)&f;
>     return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
> }

unsigned long float_bits(float f)
{
    unsigned char* bytes=(unsigned char*)&f;
    return (bytes[0]<<24) | (bytes[1]<<16) | (bytes[2]<<8) | bytes[3];
}

HTH,
Michiel Salters

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Sun, 23 May 2004 04:56:12 +0000 (UTC)
Raw View
Malte Clasen wrote:

>> I was wondering why we couldn't allow reinterpret_cast to convert
>> between built-in (POD?) types with matching sizes, such as:
>>
>> unsigned i = reinterpret_cast<unsigned>(1.2f);
>
> You can already do this in a similar way:
> float f = 1.2f;
> unsigned i = *(reinterpret_cast<unsigned*>(&f));

This violates aliasing rules, as far as I can tell, so it cannot be used.
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Sun, 23 May 2004 18:19:51 +0000 (UTC)
Raw View
Gabriel Dos Reis wrote:

>> I was wondering why we couldn't allow reinterpret_cast to convert
>> between built-in (POD?) types with matching sizes, such as:
>>
>> unsigned i = reinterpret_cast<unsigned>(1.2f);
>>
>> Of course, the result would be implementation defined. We could even
>> mandate that if you reinterpret-cast it back to the original type
>> the result should be unchanged. The code would be semantically
>> identical to:
>>
>> union ReinterpetCastButHarder
>> {
>>   unsigned i;
>>   float f;
>> };
>>
>> ReinterpretCastButHarder h;
>> h.f = 1.2f;
>> unsigned i = h.i;
>
> So you want something that would be semantically undefined behaviour;
> I'm not sure we need a specific wording for that in the standard :-)

Urgh, I actually thought the union trick to be safe, where "safe" means
implementation defined rather than undefined behaviour.

So now things get trickier. I know my implementation has "float" as a 4 byte
IEEE quantity, layed out in memory as little-endian. I want to access those 4
bytes (those 32bits) as they were an integer, to play with its bits. Is there
*any* way to do this in C++ in a way that does not yield undefined behaviour
(but just an implementation defined result)?

My suggestion was to enhance C++ with the reinterpret_cast<int>(f) syntax
exactly for this.

>> but with a much nicer syntax. After all, if the two types have the
>> same size, there must be a common bit representation.
>
> Ah, no no.  Think of a permutation of the bits without a fixed point.

Sorry, I don't follow you. Can you please elaborate?
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: kuyper@wizard.net (James Kuyper)
Date: Tue, 25 May 2004 05:55:01 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") wrote in message news:<SwUrc.15527$Wc.559978@twister2.libero.it>...
..
> So now things get trickier. I know my implementation has "float" as a 4 byte
> IEEE quantity, layed out in memory as little-endian. I want to access those 4
> bytes (those 32bits) as they were an integer, to play with its bits. Is there
> *any* way to do this in C++ in a way that does not yield undefined behaviour
> (but just an implementation defined result)?

unsigned long float_bits(float f)
{
    unsigned char* bytes=(unsigned char*)&f;
    return (bytes[0]<<6) + (bytes[1]<<4) + (bytes[2]<<2) + bytes[3];
}

If you know that 'int' is 32 bits on that platform, you can use
unsigned int rather than unsigned long.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: noway@sorry.com ("Giovanni Bajo")
Date: Sat, 15 May 2004 05:06:49 +0000 (UTC)
Raw View
Hello,

I was wondering why we couldn't allow reinterpret_cast to convert between
built-in (POD?) types with matching sizes, such as:

unsigned i = reinterpret_cast<unsigned>(1.2f);

Of course, the result would be implementation defined. We could even mandate
that if you reinterpret-cast it back to the original type the result should be
unchanged. The code would be semantically identical to:

union ReinterpetCastButHarder
{
  unsigned i;
  float f;
};

ReinterpretCastButHarder h;
h.f = 1.2f;
unsigned i = h.i;

but with a much nicer syntax. After all, if the two types have the same size,
there must be a common bit representation.
--
Giovanni Bajo

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gennaro_prota@yahoo.com (Gennaro Prota)
Date: Sat, 15 May 2004 15:56:06 +0000 (UTC)
Raw View
On Sat, 15 May 2004 05:06:49 +0000 (UTC), noway@sorry.com ("Giovanni
Bajo") wrote:

>union ReinterpetCastButHarder
>{
>  unsigned i;
>  float f;
>};
>
>ReinterpretCastButHarder h;
>h.f = 1.2f;
>unsigned i = h.i;

This is undefined behavior, as you read a member different from the
last one stored. BTW, the pair integral type/floating point type is
one of the most likely to give problems; it's easy, for instance, to
store an integer that corresponds to a NaN pattern for float and cause
a floating point exception on Intel CPUs.

>but with a much nicer syntax. After all, if the two types have the same size,
>there must be a common bit representation.

They have *object representations* of the same size. But one may have
padding bits, and the other one not... or they both may have padding
bits, but not the same number of them... and one or both may have
(different) trap representations. Etc. etc. :)


Genny.

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: news@copro.org (Malte Clasen)
Date: Sun, 16 May 2004 01:31:21 +0000 (UTC)
Raw View
Hi!

Giovanni Bajo wrote:
> I was wondering why we couldn't allow reinterpret_cast to convert between
> built-in (POD?) types with matching sizes, such as:
>
> unsigned i = reinterpret_cast<unsigned>(1.2f);

You can already do this in a similar way:

float f = 1.2f;
unsigned i = *(reinterpret_cast<unsigned*>(&f));

Malte

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]





Author: gdr@cs.tamu.edu (Gabriel Dos Reis)
Date: Mon, 17 May 2004 03:01:01 +0000 (UTC)
Raw View
noway@sorry.com ("Giovanni Bajo") writes:

| Hello,
|
| I was wondering why we couldn't allow reinterpret_cast to convert between
| built-in (POD?) types with matching sizes, such as:
|
| unsigned i = reinterpret_cast<unsigned>(1.2f);
|
| Of course, the result would be implementation defined. We could even mandate
| that if you reinterpret-cast it back to the original type the result should be
| unchanged. The code would be semantically identical to:
|
| union ReinterpetCastButHarder
| {
|   unsigned i;
|   float f;
| };
|
| ReinterpretCastButHarder h;
| h.f = 1.2f;
| unsigned i = h.i;

So you want something that would be semantically undefined behaviour;
I'm not sure we need a specific wording for that in the standard :-)

| but with a much nicer syntax. After all, if the two types have the same size,
| there must be a common bit representation.

Ah, no no.  Think of a permutation of the bits without a fixed point.

--
                                                        Gabriel Dos Reis
                                                         gdr@cs.tamu.edu
  Texas A&M University -- Computer Science Department
 301, Bright Building -- College Station, TX 77843-3112

---
[ 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://www.jamesd.demon.co.uk/csc/faq.html                       ]