1

I am writing a DLL plugin for a 32bit program on Win64, compiled as Win32/Debug in Visual Studio 2015. I need to left bit-shift an unsigned char (defined upstream) by 56 bits into an UINT64, so that 0xFF should become 0xFF000000000000.

What's actually happening is that for any shift value greater than 32, the result is a shift of (shift - 32) bits, with the higher 32 bits of my target UINT64 become all-1, so that:

int     NmeaPgn::sf_get_bytes(TCanMessage *m, UINT8 start_byte, UINT8 bytes)
{
    UINT64 r = 0; /* Could need to fetch up to 8 bytes, as in 60928 */
    INT8 i;

    for (i = start_byte + bytes - 1; i >= start_byte; --i)
    {
        r |= (m->data[i] << 8 * (i - start_byte));
    }
...
}

Using the VS debugger, I see that for:

m->data[i] == 0xC0
i == 0x7
start_byte == 0
bytes == 8 (so that shift == 8 * (7 - 0) == 56)

then:
r == 0xFFFFFFFFc0000000

I have read:

https://msdn.microsoft.com/en-us/library/336xbhcz.aspx

C++ bitwise left shift by 32

Left shift an integer by 32 bits

The closest to an answer I can see is Andrey Nasonov's answer (https://stackoverflow.com/a/33058550/7817631) to the latter, but I am on a 64-bit machine (Win7-64 on Core i5), so I would not expect this to be directly relevant.

Community
  • 1
  • 1
TomGreen
  • 41
  • 3
  • Probably `m->data[i]` is a 32-bit value (or smaller) . BTW you should not edit solutions into the question, instead you can post an answer. (Although maybe there is a min rep requirement for answering your own question, IDK). – M.M Apr 05 '17 at 03:14
  • 1
    Please don't post answer in question. You can [answer](https://stackoverflow.com/help/self-answer) your own question. – zhm Apr 05 '17 at 03:18
  • 2
    @MartinZhai according to that link 15 rep is required, so I guess OP is out of luck in this case – M.M Apr 05 '17 at 03:28
  • If the debugger says that `m->data[i]` is `0xC0` then it is probably a byte (8 bit quantity) - promoted to `int` according to the standard promotion rules. `int` being 32 bits on your compiler ... you get a 32 bit shift. In fact you could have legally gotten any result whatsover from [time travel](https://blogs.msdn.microsoft.com/oldnewthing/20140627-00/?p=633/) to program termination since the result of a shift larger than the size of the integral value being shifted is undefined in C++ - [here's an answer to that effect](http://stackoverflow.com/a/9860578/751579). – davidbak Apr 05 '17 at 03:48
  • BTW, you could have figured this out yourself if you had pared down your example to a [mcve] - a very useful discovery technique. – davidbak Apr 05 '17 at 03:54
  • Since it needs 15 rep to answer a question, I think this is as good as it can be. You can move the solution to a real answer after have enough rep. :-) – zhm Apr 05 '17 at 05:18

1 Answers1

0

(Since TomGreen can't answer his own questions yet, here's his answer)

I had to explicitly cast my unsigned char to UINT64 as follows:

r |= ((UINT64)m->data[i] << 8 * (i - start_byte));

This produces the expected value (0xC000000000) where m->data[i] == 0xC0 and shift == 56.

MSalters
  • 173,980
  • 10
  • 155
  • 350