On Fri, 11 Apr 2008 15:33:41 CST, Olivier Langlois
<olanglois@[EMAIL PROTECTED]
> wrote in comp.lang.c++.moderated:
> Hi,
>
> I was expecting:
>
> int main( int argc, char *argv[] )
> {
> unsigned char m = 32;
> register unsigned mask = (1<<m);
> std::cout << std::hex << mask << '\n';
> return 0;
> }
>
> to print 0 but instead this program compiled with g++ prints 1!
>
> If I change (1<<m) by (1<<32) or if change the program for
>
> int main( int argc, char *argv[] )
> {
> unsigned char m = 31;
> register unsigned mask = (1<<m)<<1;
> std::cout << std::hex << mask << '\n';
> return 0;
> }
>
> it gives me the expected 0.
>
> In the C++ standard do***ent, section 5.8. It is written "The behavior
> is undefined if the right operand is negative, or greater than or
> equal to the length in bits of the promoted left operand."
>
> The root for this behavior probably originates from C but I am really
> curious why the standard makes the ****ft operator so unintuitive.
The ****ft operator mimics the underlying behavior of the hardware,
which differs on various architectures. This is exactly the same
reason that right ****fting negative signed values and signed value
overflow have undefined results, namely because what the underlying
hardware does can be different.
Nowadays, most modern processors mask the ****ft value before it goes
to the ****fter hardware. When ****fting a 32-bit register, they mask
the ****ft argument with 0x1f. This is especially true of processors
with barrel ****fters that can ****ft by any number in a single cycle,
instead of one cycle per bit ****fted.
In many ways, C++ shares one of the most im****tant features of C,
namely, you don't pay for what you don't use. The vast majority of
programs never try to ****ft a value by too many bits, so the source
statement turns into the minimal object code to use the hardware ****ft
instruction.
If you want a size safe ****ft operator, just as if you want overflow
and underflow safe arithmetic operators, define functions for that
purpose and only call them, and pay for the extra overhead, when the
safety is needed.
Example, almost but not universally ****table:
#include <climits>
/* include at least one header that defines std::sizeof */
unsigned int safe_uint_****ft(unsigned int value, unsigned int bits)
{
if (bits > (CHAR_BIT * std::sizeof(unsigned int)) return 0;
else return value << bits;
}
Put it in a header and make it inline if you like.
That is essentially what you are asking he compiler to do for you, but
many other programs don't want or need the extra check.
--
Jack Klein
Home: http://JK-Technology.Com
FAQs for
comp.lang.c http://c-faq.com/
comp.lang.c++ http://www.para****ft.com/c++-faq-lite/
alt.comp.lang.learn.c-c++
http://www.club.cc.cmu.edu/~ajo/docs/FAQ-acllc.html
[ See http://www.gotw.ca/resources/clcm.htm
for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]


|