Bit shifting trouble

Go To Last Post
4 posts / 0 new
Author
Message
#1
  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Hello, I am having a problem using bit shift operators on unsigned 32-bit integers. Here is the problem. I am programming for avr mega2560. I am using Atmel Studio 6.2 with the latest 8-bit toolchain available through the extension manager. When I do the following:

 

unsigned long my_var = 0;

my_var |= 0x00000001 << 16;

 

The compiler gives the following warning: 

 

my_program.c:22:1: warning: left shift count >= width of type [enabled by default] my_var |= ( 0x00000001 << 16);

 

The value stored in my_var after this operation is: 0xFFFF0000. Bit shifting by more spaces causes the bit I want to set AND every higher-numbered bit to all be set to '1'. I get the same behavior when using the explicit uint32_t type (I realize this is just a typedef of unsigned long). I have also tried shorter bitmasks, ie. 0x01. Same result.

 

I cannot figure out why this is happening. If I bit shift by <16 spaces everything is fine. It stops working when shifting by 16 spaces or more. 

 

Can anyone explain what is going on?

 

On a (perhaps) related note I see that there is a new version of AVR 8-bit toolchain available to download from Atmel on their web site as of 11/2014, but this version is not available in the Atmel Studio Extension Manager. The splash on the avr-gcc I'm using shows (from Atmel Studio) shows the following version at compile time: AVR_8_bit_GNU_Toolchain_3.4.4_1229. I downloaded the new version, and "avr-gcc -v" gives the following: AVR_8_bit_GNU_Toolchain_3.4.5_1522. Both are gcc version 4.8.1. I'm not 100% sure how I'd overwrite the older version without messing up my environment but I'm willing to give it a shot if anyone thinks it might help & cares to walk me through it. 

 

Thanks!

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Constants will usually be of the default size of an int on your processor, so for the AVRs this will be a 16-bit value.
Your 0x00000001 will be converted to 16-bits (0x0001) and the compiler checks and discovers that shifting a 16-bit value by more than 15 bits will give you a zero result.
The solution is to force the shifting to be done in a 32-bit mode and the simplest way to do that is with the UL 'unsigned long' modifier on the constant, ie. 0x00000001UL

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

Thanks, this fixed it! I initially suspected this was a data typing issue and one of the things I had tried was forcing right-hand input the bit shift argument to be 32-bits (my_var |= 0x00000001 << 16UL;). I assumed that this would cause promotion of all terms to UL but of course it didn't. I'm just curious why the left operator wasn't promoted when the right operator was UL, if you don't mind me asking? Is it my understanding of automatic type promotion that is incorrect; or does promotion only occur when using math operators and not bit operators? Anyway, thanks again. 

  • 1
  • 2
  • 3
  • 4
  • 5
Total votes: 0

With the most recent standard, if x and y have integer types, x<<y has the type of x.

As a result of misplaced orthogonality, it used to have the same type as x*y.

Iluvatar is the better part of Valar.