31

So I'm building an MSNP (windows live messenger) client. And I've got this list of capabilities

public enum UserCapabilities : long
{
    None = 0,
    MobileOnline = 1 << 0,
    MSN8User = 1 << 1,
    RendersGif = 1 << 2,
    ....
    MsgrVersion7 = 1 << 30,
    MsgrVersion8 = 1 << 31,
    MsgrVersion9 = 1 << 32,
}

full list here http://paste.pocoo.org/show/383240/

The server sends each users capabilities to the client as a long integer, which I take and cast it to UserCapabilities

capabilities = Int64.Parse(e.Command.Args[3]);
user._capabilities = (UserCapabilities)capabilities;

This is fine, and with atleast one user (with a capability value of 1879474220), I can do

Debug.WriteLine(_msgr.GetUser(usr).Capabilities);

and this will output

RendersGif, RendersIsf, SupportsChunking, IsBot, SupportsSChannel, SupportsSipInvite, MsgrVersion5, MsgrVersion6, MsgrVersion7

But with another user, who has the capability value of (3055849760), when I do the same, I just get the same number outputted

3055849760

What I would like to be seeing is a list of capabilities, as it is with the other user.

I'm sure there is a very valid reason for this happening, but no matter how hard I try to phrase the question to Google, I am not finding an answer.

Please help me :)

leppie
  • 115,091
  • 17
  • 196
  • 297
NoPyGod
  • 4,905
  • 3
  • 44
  • 72

2 Answers2

32

The definition of the shift operators means that only the 5 least significant bits are used for 32-bit numbers and only the first 6 bits for 64-bit; meaning:

1 << 5

is identical to

1 << 37

(both are 32)

By making it:

MsgrVersion9 = 1L << 32

you make it a 64-bit number, which is why @leppie's fix works; otherwise the << is considered first (and note that 1<<32 is identical to 1<<0, i.e. 1), and then the resulting 1 is converted to a long; so it is still 1.

From §14.8 in the ECMA spec:

For the predefined operators, the number of bits to shift is computed as follows:

  • When the type of x is int or uint, the shift count is given by the low-order five bits of count. In other words, the shift count is computed from count & 0x1F.
  • When the type of x is long or ulong, the shift count is given by the low-order six bits of count. In other words, the shift count is computed from count & 0x3F.

If the resulting shift count is zero, the shift operators simply return the value of x.

Shift operations never cause overflows and produce the same results in checked and unchecked context

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • It might not be called 'overflow' but the effect is the same, ie `(1L << 33) & 0xffffffff`. I think the spec text implies that an overflow exception will never be thrown when shifting. – leppie May 05 '11 at 08:27
  • 3
    @leppie - but if it was just the avoidance of overflow, then you should expect that (for `int`) anything `<<32` would be zero; the same as shifting it `<<16` twice (which it isn't). – Marc Gravell May 05 '11 at 08:28
10

The problem could be with arithmetic overflow.

Specifically at:

MsgrVersion8 = 1 << 31,
MsgrVersion9 = 1 << 32,

I suggest you make it:

MsgrVersion8 = 1L << 31,
MsgrVersion9 = 1L << 32,

To prevent accidental overflow.

Update:

Seems likely as the smaller number on 'touches' 31 bits, while the bigger one 'touches' 32 bits.

leppie
  • 115,091
  • 17
  • 196
  • 297
  • 4
    The reason is simple: 1 is `Int32` and 31 is also `Int32`, the result again is `Int32`, which is a signed int, which has a maximum value of 2,147,483,647, but 1 << 31 is 2,147,483,648, so it will overflow to -2,147,483,648. – Daniel Hilgarth May 05 '11 at 07:21
  • 4
    @Daniel @NoPyGod this is nothing to do with overflow; see my answer – Marc Gravell May 05 '11 at 08:11