C++Talk.NET Forum Index C++Talk.NET
C++ language newsgroups
 
Archives   FAQFAQ   SearchSearch   MemberlistMemberlist   UsergroupsUsergroups   RegisterRegister 
 ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

reinterpret_cast to extract bits
Goto page 1, 2, 3  Next
 
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards
View previous topic :: View next topic  
Author Message
Giovanni Bajo
Guest





PostPosted: Sat May 15, 2004 5:06 am    Post subject: reinterpret_cast to extract bits Reply with quote



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 ]

Back to top
Gennaro Prota
Guest





PostPosted: Sat May 15, 2004 3:56 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote



On Sat, 15 May 2004 05:06:49 +0000 (UTC), [email]noway (AT) sorry (DOT) com[/email] ("Giovanni
Bajo") wrote:

Quote:
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.

Quote:
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 ]


Back to top
Malte Clasen
Guest





PostPosted: Sun May 16, 2004 1:31 am    Post subject: Re: reinterpret_cast to extract bits Reply with quote



Hi!

Giovanni Bajo wrote:
Quote:
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 ]


Back to top
Gabriel Dos Reis
Guest





PostPosted: Mon May 17, 2004 3:01 am    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]noway (AT) sorry (DOT) com[/email] ("Giovanni Bajo") writes:

Quote:
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 :-)

Quote:
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
[email]gdr (AT) cs (DOT) tamu.edu[/email]
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 ]


Back to top
Giovanni Bajo
Guest





PostPosted: Sun May 23, 2004 4:56 am    Post subject: Re: reinterpret_cast to extract bits Reply with quote

Malte Clasen wrote:

Quote:
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 ]


Back to top
Giovanni Bajo
Guest





PostPosted: Sun May 23, 2004 6:19 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

Gabriel Dos Reis wrote:

Quote:
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 Smile

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.

Quote:
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 ]


Back to top
James Kuyper
Guest





PostPosted: Tue May 25, 2004 5:55 am    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]noway (AT) sorry (DOT) com[/email] ("Giovanni Bajo") wrote in message news:<SwUrc.15527$Wc.559978 (AT) twister2 (DOT) libero.it>...
...
Quote:
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 ]


Back to top
Michiel Salters
Guest





PostPosted: Wed May 26, 2004 2:21 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]kuyper (AT) wizard (DOT) net[/email] (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b (AT) posting (DOT) google.com>...

Quote:
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]<<Cool | 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 ]


Back to top
James Kuyper
Guest





PostPosted: Thu May 27, 2004 9:11 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]Michiel.Salters (AT) logicacmg (DOT) com[/email] (Michiel Salters) wrote in message news:<fcaee77e.0405260232.307d0c2b (AT) posting (DOT) google.com>...
Quote:
kuyper (AT) wizard (DOT) net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b (AT) posting (DOT) 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]<<Cool | 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 ]


Back to top
Dave Thompson
Guest





PostPosted: Tue Jun 01, 2004 5:06 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

On Wed, 26 May 2004 14:21:59 +0000 (UTC),
[email]Michiel.Salters (AT) logicacmg (DOT) com[/email] (Michiel Salters) wrote:

Quote:
kuyper (AT) wizard (DOT) net (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b (AT) posting (DOT) 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]<<Cool | 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 ]


Back to top
James Kuyper
Guest





PostPosted: Wed Jun 02, 2004 8:28 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]david.thompson1 (AT) worldnet (DOT) att.net[/email] (Dave Thompson) wrote in message news:<0grnb0djk1e7dd8llriurc3eg2bec4t2fs (AT) 4ax (DOT) com>...
Quote:
On Wed, 26 May 2004 14:21:59 +0000 (UTC),
[email]Michiel.Salters (AT) logicacmg (DOT) com[/email] (Michiel Salters) wrote:

[email]kuyper (AT) wizard (DOT) net[/email] (James Kuyper) wrote in message news:<8b42afac.0405240634.3ba3dc6b (AT) posting (DOT) 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]<<Cool | 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.

Quote:
... 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.

Quote:
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 ]


Back to top
Giovanni Bajo
Guest





PostPosted: Thu Jun 03, 2004 5:25 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

James Kuyper wrote:

Quote:
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 ]


Back to top
James Kuyper
Guest





PostPosted: Thu Jun 03, 2004 9:56 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]noway (AT) sorry (DOT) com[/email] ("Giovanni Bajo") wrote in message news:<09vvc.34206$Wc.1158868 (AT) twister2 (DOT) libero.it>...
Quote:
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 ]


Back to top
Giovanni Bajo
Guest





PostPosted: Fri Jun 04, 2004 4:04 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

James Kuyper wrote:

Quote:
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 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 ]


Back to top
Sergei Organov
Guest





PostPosted: Fri Jun 04, 2004 4:05 pm    Post subject: Re: reinterpret_cast to extract bits Reply with quote

[email]kuyper (AT) wizard (DOT) net[/email] (James Kuyper) writes:
Quote:
noway (AT) sorry (DOT) 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 ]


Back to top
Display posts from previous:   
Post new topic   Reply to topic    C++Talk.NET Forum Index -> C++ language, library and standards All times are GMT
Goto page 1, 2, 3  Next
Page 1 of 3

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2006 phpBB Group
SEO toolkit © 2004-2006 webmedic.