Bit offset with unsigned long type leads to incorrect results

I'm a little confused because I wanted to initialize a type variable unsigned long

that is 8 bytes in size on my system (on every modern system, I suppose). When I want to assign to a variable 1 << 63

, I get a compiler warning and the number is actually 0. When I do 1 << 30

, I get the expected result 2 ^ 30 = 1073741824

. But when I do 1 << 31

, I get a result 2 ^ 64

(I guess it shouldn't actually be possible) that prints 18446744071562067968

.

Can anyone explain this behavior to me?

+3


source to share


4 answers


1 << 63

will be calculated in arithmetic int

, and yours int

is probably 32 bits.

Eliminate this by promoting one of the arguments: 1ULL << 63

will do it.



ULL

means the expression will be at least 64 bits.

+8


source


The expression 1 << 63

is of type int

. The range int

is -2 31 ... 2 31 - 1 on most systems, 2 63 is too much for this. Try to either (unsigned long)1 << 63

or 1UL << 63

shift the value of the type unsigned long

left by 63 places.



+2


source


I recommend using 1ULL

as this will give you an unsigned 64 bit integer on 32 and 64 bit architectures. On a 32 bit architecture unsigned long

(and therefore UL

) the length is only 32 bits and will not solve the problem.

1ULL << 63

      

+2


source


This 1

is referred to as an integer constant. According to the norms specified in the standard C11

, chapter ยง6.4.4.1

, the syntax for it is

integer constant: decimal-constant integer-suffix opt
      octal integer-suffix constant opt       hexadecimal constant integer-suffix <sub> manualsub>

and regarding semantics,

The type of an integer constant is the first in the corresponding list in which its value can be represented.

and the table states that if there is no suffix and the value is presented in a range int

, it should be treated as int

. So 1

what is considered here as int

which usually has 4 bytes or 32 bits is also the same in your case.

To explicitly specify a bit 1

as unsigned long

(64), we can use a suffix like

1UL << 63

      

should solve your problem.

Please note: unsigned long

it cannot be 64 bits. unsigned long long

guaranteed to have at least 64 bits
. However, as long as you are using a platform where it unsigned long

has 64 bits, you should be fine

+1


source







All Articles