 |
C++Talk.NET C++ language newsgroups
|
| View previous topic :: View next topic |
| Author |
Message |
Le Chaud Lapin Guest
|
Posted: Thu Apr 15, 2004 7:40 pm Post subject: const_cast<>() on bitfield |
|
|
The following code causes a memory access exception but generates no
compiler warnings (Visual Studio 6.0).
I felt I would be asking too much trying to cast a bitfield to
reference to its super space, but should not the compiler not warn
about code like this?
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
-Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Fri Apr 16, 2004 5:07 pm Post subject: Re: const_cast<>() on bitfield |
|
|
[email]unoriginal_username (AT) yahoo (DOT) com[/email] (Le Chaud Lapin) wrote in message
news:<fc2e0ade.0404140828.623716b1 (AT) posting (DOT) google.com>...
| Quote: | The following code causes a memory access exception but generates no
compiler warnings (Visual Studio 6.0).
I felt I would be asking too much trying to cast a bitfield to
reference to its super space, but should not the compiler not warn
about code like this?
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
|
There are actually two problems in the code. The first is that you are
trying to obtain a reference to a bit field -- I think that this is
illegal, and that the compiler should complain, but I'm not sure about
this specific instance. (You can create a const reference to a bit
field, for example, but the actual reference should refer to a temporary
variable initialized with the contents of the bit field.)
The second problem is that you are trying to modify a const object
(extent), which is undefined behavior. So the compiler is not required
to say anything.
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Matani Guest
|
Posted: Sat Apr 17, 2004 6:15 am Post subject: Re: const_cast<>() on bitfield |
|
|
On Thu, 15 Apr 2004 15:40:51 -0400, Le Chaud Lapin wrote:
| Quote: | The following code causes a memory access exception but generates no
compiler warnings (Visual Studio 6.0).
I felt I would be asking too much trying to cast a bitfield to
reference to its super space, but should not the compiler not warn
about code like this?
|
Why should it? You have explicitly told that compiler that you know what
you are doing by using the explicit const_cast<>. Now it is not necessary
that all conatants should be stored in read-write memory. They may be
stored in read-only memory, hence the access violation.
| Quote: | struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
|
Regards,
-Dhruv.
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Le Chaud Lapin Guest
|
Posted: Sun Apr 18, 2004 12:36 am Post subject: Re: const_cast<>() on bitfield |
|
|
"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
| Quote: | On Thu, 15 Apr 2004 15:40:51 -0400, Le Chaud Lapin wrote:
The following code causes a memory access exception but generates no
compiler warnings (Visual Studio 6.0).
[snip]
Why should it? You have explicitly told that compiler that you know what
you are doing by using the explicit const_cast<>. Now it is not necessary
that all conatants should be stored in read-write memory. They may be
stored in read-only memory, hence the access violation.
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
|
Good point, but I do not think that is what is causing the exception
in this case. I think the compiler is generating code that is
accessing memory out of bounds. I believe this because it is possible
to have a non-const 'foo' with most of its members being non-const
except for 'extent', which is const. If such an object is to be
allocated at run-time in read/write memory, then, in general, the
compiler has no choice but to put the entire 'foo' in read/write
memory.
-Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Matani Guest
|
Posted: Sun Apr 18, 2004 10:01 am Post subject: Re: const_cast<>() on bitfield |
|
|
On Sat, 17 Apr 2004 20:36:24 -0400, Le Chaud Lapin wrote:
| Quote: | "Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
On Thu, 15 Apr 2004 15:40:51 -0400, Le Chaud Lapin wrote:
The following code causes a memory access exception but generates no
compiler warnings (Visual Studio 6.0).
[snip]
Why should it? You have explicitly told that compiler that you know what
you are doing by using the explicit const_cast<>. Now it is not necessary
that all conatants should be stored in read-write memory. They may be
stored in read-only memory, hence the access violation.
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
Good point, but I do not think that is what is causing the exception
in this case. I think the compiler is generating code that is
accessing memory out of bounds. I believe this because it is possible
to have a non-const 'foo' with most of its members being non-const
except for 'extent', which is const. If such an object is to be
allocated at run-time in read/write memory, then, in general, the
compiler has no choice but to put the entire 'foo' in read/write
memory.
|
However, as an optimization, the compiler may eliminate the space required
for extent completely because it is constant! So, refering to it for a
write to extent would be a total mistake. Use const_cast with extreme
care. ints and small PODs are easily optimized by compilers. Also, the
standard does not guarantee correct behaviour when const_cast is applied
to actually const objects.
Do this:
struct Test
{
const unsigned int extent1 : 31;
const unsigned int extent2 : 31;
};
struct Empty { };
And see the output of sizeof(Test) for your compiler.
Assume that sizeof(Empty) = x.
sizeof(unsigned int) = x.
Then if sizeof(Test) == 2*sizeof(Empty), then everything is fine, else
optimization is taking place.
--
Regards,
-Dhruv.
Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Le Chaud Lapin Guest
|
Posted: Mon Apr 19, 2004 5:48 am Post subject: Re: const_cast<>() on bitfield |
|
|
"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
| Quote: | [snip]
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
However, as an optimization, the compiler may eliminate the space required
for extent completely because it is constant! So, refering to it for a
write to extent would be a total mistake. Use const_cast with extreme
care. ints and small PODs are easily optimized by compilers. Also, the
standard does not guarantee correct behaviour when const_cast is applied
to actually const objects.
|
Perhaps I misunderstand the notion of a const data member. I thought
them const member of each object of a class is entitled to its own
unique value. Otherwise, a static const member could be used. If this
is the case, then the compiler has no way of knowing at any given
moment what value an object's const member should assume, forcing it
allocate some space within the object even though it is logically
immutable.
| Quote: | Do this:
struct Test
{
const unsigned int extent1 : 31;
const unsigned int extent2 : 31;
};
struct Empty { };
And see the output of sizeof(Test) for your compiler.
Assume that sizeof(Empty) = x.
sizeof(unsigned int) = x.
Then if sizeof(Test) == 2*sizeof(Empty), then everything is fine, else
optimization is taking place.
|
I got 8 for sizeof(Test) and 2 for 2*sizeof(Empty) using Visual C++
6.0 with structure packing not enabled.
-Chaud Lapin-
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
Dhruv Matani Guest
|
Posted: Mon Apr 19, 2004 6:53 pm Post subject: Re: const_cast<>() on bitfield |
|
|
On Mon, 19 Apr 2004 01:48:51 -0400, Le Chaud Lapin wrote:
| Quote: | "Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
[snip]
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
However, as an optimization, the compiler may eliminate the space required
for extent completely because it is constant! So, refering to it for a
write to extent would be a total mistake. Use const_cast with extreme
care. ints and small PODs are easily optimized by compilers. Also, the
standard does not guarantee correct behaviour when const_cast is applied
to actually const objects.
Perhaps I misunderstand the notion of a const data member. I thought
them const member of each object of a class is entitled to its own
unique value. Otherwise, a static const member could be used. If this
is the case, then the compiler has no way of knowing at any given
moment what value an object's const member should assume, forcing it
allocate some space within the object even though it is logically
immutable.
|
No, you are right. All I'm saying is that the compiler may optimize it out
because:
1. There is not ctor, and no initialization is being done for the consrt
members.
2. The main function is not mentioned, and so I assume that there is no
brace inituializer which will initialize structs not having any ctor.
Most of the compilers will surely reserve space, but I guess this
optimization is probably permissible.
| Quote: | I got 8 for sizeof(Test) and 2 for 2*sizeof(Empty) using Visual C++
6.0 with structure packing not enabled.
|
Ok, so apparently VC6.0 does not dword align empty structs. You should be
fine then.
However, getting back to your original problem, here is an absolutely
non-portable solution ;-)
#include <iostream>
using namespace std;
struct Test
{
const unsigned int t1 : 4;
const unsigned int t2 : 31;
};
void write_to_t1(unsigned int value, Test& _t)
{
//Get the dword/word/etc... that encompassed the bit-field.
char _temp = _t.t1;
//Set the last 4 bits.
value &= 15;
char _t1 = _temp;
_t1 >>= 4;
_t1 <<= 4;
_temp &= _t1;
_temp |= value;
*(char*)&_t = _temp;
}
int main()
{
Test t = {2, 45};
cout<
write_to_t1(5, t);
cout<
cout<
}
--
Regards,
-Dhruv.
Proud to be a Vegetarian.
http://www.vegetarianstarterkit.com/
http://www.vegkids.com/vegkids/index.html
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Tue Apr 20, 2004 10:04 am Post subject: Re: const_cast<>() on bitfield |
|
|
"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
| Quote: | On Thu, 15 Apr 2004 15:40:51 -0400, Le Chaud Lapin wrote:
The following code causes a memory access exception but generates
no compiler warnings (Visual Studio 6.0).
I felt I would be asking too much trying to cast a bitfield to
reference to its super space, but should not the compiler not warn
about code like this?
Why should it? You have explicitly told that compiler that you know
what you are doing by using the explicit const_cast<>.
|
Yes and no. The whole purpose behind the new style casts is that you
can't say just anything using them. In this case, the const_cast is a
lie, and so he cannot count on anything after that, but that isn't the
only problem. The problem is that you cannot have a reference to a
bit-field. This is clear in §8.5.3/5; I think it is probably a defect
in the standard that §5.2.11 doesn't mention this. (As far as I can
tell, implementing §5.2.11/4 to work on a bit-field simply isn't
possible, and I presume that the standard meant to forbid it, but
forgot.)
It would be interesting to see the generated code. (None of the
compilers I have access to accept it, const or not.)
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
kanze@gabi-soft.fr Guest
|
Posted: Tue Apr 20, 2004 11:33 pm Post subject: Re: const_cast<>() on bitfield |
|
|
"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote
| Quote: | On Mon, 19 Apr 2004 01:48:51 -0400, Le Chaud Lapin wrote:
"Dhruv Matani" <dhruvbird (AT) gmx (DOT) net> wrote in message
news:<pan.2004.04.18.04.28.21.827821 (AT) gmx (DOT) net>...
[snip]
struct Foo
{
// ...
const unsigned int extent : 31;
} foo;
const_cast<unsigned int &>(foo.extent) >>= 1;
However, as an optimization, the compiler may eliminate the space
required for extent completely because it is constant! So,
refering to it for a write to extent would be a total
mistake. Use const_cast with extreme care. ints and small PODs
are easily optimized by compilers. Also, the standard does not
guarantee correct behaviour when const_cast is applied to
actually const objects.
Perhaps I misunderstand the notion of a const data member. I
thought them const member of each object of a class is entitled to
its own unique value. Otherwise, a static const member could be
used. If this is the case, then the compiler has no way of knowing
at any given moment what value an object's const member should
assume, forcing it allocate some space within the object even though
it is logically immutable.
No, you are right. All I'm saying is that the compiler may optimize it
out because:
1. There is not ctor, and no initialization is being done for the
const members.
|
That isn't even legal. G++ accepts it, but that is a bug in the
compiler. Sun CC doesn't. §8.5/9 says:
If no initializer is specified for an object, and the object is of
(possibly cv-qualified) non-POD class type (or array thereof), the
object shall be default-initialized; if the object is of
const-qualified type, the underlying class type shall have a
user-declared default constructor. Otherwise, if no initializer is
specified for an object, the object and its subobjects, if any, have
an indeterminate initial value; if the object or any of its
subobjects are of const-qualified type, the program is ill-formed.
The first sentence doesn't apply here, since we have a POD class type,
and we end up in the second clause of the last sentence -- "if no
intializer is specified for an object [...]; if [...] any of its
subobjects are of const-qualified type, the program is ill-formed."
Ill-formed programs require a diagnostic.
| Quote: | 2. The main function is not mentioned, and so I assume that there is
no brace inituializer which will initialize structs not having any
ctor.
|
His definition of foo, above, doesn't contain any initializer. A third
reason why the program is illegal.
| Quote: | Most of the compilers will surely reserve space, but I guess this
optimization is probably permissible.
|
A conformant C++ compiler will not even compile the code -- the
definition of foo doesn't contain an initializer. Most C++ will not
compile the code either, because he (indirectly) attempts to take the
address of a bitfield (that is what casting an lvalue to a reference
implicitly does). And once we've got that, he attempts to modify a
const object -- undefined behavior.
| Quote: | I got 8 for sizeof(Test) and 2 for 2*sizeof(Empty) using Visual C++
6.0 with structure packing not enabled.
Ok, so apparently VC6.0 does not dword align empty structs.
|
Do you know of any compiler which does? (I imagine those for word
addressed machines do, but word addressed machines aren't that commun
now adays.) I recently needed some structures consisting of arrays of
char, to format some header blocks. are other solutions, but Some of
the header blocks had very odd sizes -- 29 bytes, or whatever. So I did
some testing. I was unable to find a compiler where this didn't work.
(There are other solutions, some, unlike this one, guaranteed by the
standard. But globally, this seemed the clearest and the easiest to
read in context. So, with a good comment explaining the risk, and a few
asserts that the sizeof the structs was really what I wanted, I used
it.)
| Quote: | You should be fine then.
However, getting back to your original problem, here is an absolutely
non-portable solution
|
Whereas a fully portable solution exists.
| Quote: | #include <iostream
using namespace std;
struct Test
{
const unsigned int t1 : 4;
const unsigned int t2 : 31;
};
void write_to_t1(unsigned int value, Test& _t)
{
//Get the dword/word/etc... that encompassed the bit-field.
char _temp = _t.t1;
//Set the last 4 bits.
value &= 15;
char _t1 = _temp;
_t1 >>= 4;
_t1 <<= 4;
_temp &= _t1;
_temp |= value;
*(char*)&_t = _temp;
}
|
What's wrong with:
void
writeToT1( unsigned value, Test& t )
{
t.t1 = value ;
}
Guaranteed to work, by the standard.
If you need to have bits at a specific place in a word, portably, you
cannot use bitfields -- the Sun compiler packs them starting with the
top bit of the word, where as other compilers I have used started at the
bottom (which somehow seems more natural to me, but is certainly not
required, or even recommended, by the standard). If you are only
concerned with a single compiler, and it happens to lay things out like
you want, on the other hand...
If you do need to position bits exactly, your code still seems a little
shaky. First, I'd definition do the masking and the shifting on
something larger than a char, and I'd definitly do it using unsigned
types only, to be sure that there wasn't any sign extension in the right
shifts. Beyond that, the classical idiom for setting bits m-n in a word
is:
unsigned const mask = ~0 << n & ~( ~0 << m ) ;
word = (word & mask) | (newValue << m) & mask ;
(That's off the top of my head, so there may be an off by one error in
there, but you get the general idea.)
I generally declare the masks and the shift counts as named fields.
Thus, to extract the exponent from an IEEE double, I would do something
like:
typedef unsigned short*
Raw ;
#if HIBYTE1ST
static int const exponentIndex = 0 ;
#else
static int const exponentIndex = 3 ;
#endif
static Raw const exponentMask = 0x7FF0 ;
static int const exponentShift = 4 ;
static int const exponentOffset = 1022 ;
void
setExponent( double& dest, int newExp )
{
Raw* p = reinterpret_cast< Raw* >( &dest ) ;
p[ exponentIndex ] =
(p[ exponentIndex ] & ~ exponentMask)
| Quote: | (((newExp + 1022 << exponentShift) & exponentMask ;
} |
int
getExponent( double const& source )
{
Raw const* p = reinterpret_cast< Raw const* >( &source ) ;
return ((p[ exponentIndex ] & exponentMask) >> exponentIndex)
- exponentOffset ;
}
(I might add that in 30 years of programming, the only code I ever wrote
which depended on the byte ordering was code to play around with the
different fields of a double.)
--
James Kanze GABI Software mailto:kanze (AT) gabi-soft (DOT) fr
Conseils en informatique orientée objet/ http://www.gabi-soft.fr
Beratung in objektorientierter Datenverarbeitung
9 place Sémard, 78210 St.-Cyr-l'École, France, +33 (0)1 30 23 00 34
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]
|
|
| Back to top |
|
 |
|
|
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
|
|