1

ALL,

long long unsigned int bigvalue;
bigvalue = (codeword[0] & 0XFFFC) >> 2;
bigvalue |= (codeword[1] & 0XFFFF) << 14;
bigvalue |= (codeword[2] & 0XFFFF) << 30;
bigvalue |= (codeword[3] & 0XFFFF) << 46;

codeword is of type guint16.

I am getting an error on the last line: left shift count >= width of type.

What would be the way to mitigate?

TIA!!

EDIT:

There was a suggested answer. However the question is completely different. I'm asking about compiler error amd the referenced question is about the wrong result.

EDIT2:

To give a little more context - that piece of code is suppose to parse the WS stream (it is inside the dissector). The code is auto-generated by the Perl script from the set of rules. I'm trying to fix an issue where the code is crashing because the last line is not there.

The field that should be parsed is 68 bits long and it is read into 5 elements - codeword[i]. In front of it is 2 bits indicator, hence 0xfffc in the second line.

I will try casting and report back tomorrow.

Thank you.

EDIT3:

Please, please, please stop suggesting completely unrelated to this one questions as solutions! They don't have anything in common!!

Thank you.

Igor
  • 5,620
  • 11
  • 51
  • 103
  • 4
    What is `codeword`? Please provide a **complete** example. `guint16` means nothing by itself. – Andrew Henle Jun 18 '21 at 04:13
  • 1
    suppose `guint16` is narrower than int then it'll be promoted to int, which doesn't have 64 bits in your platform and [shifting more bits than the width of type invokes UB](https://stackoverflow.com/q/11270492/995714). You must cast the left operand to `unsigned long long`. Duplicates: [bit shifting with unsigned long type produces wrong results](https://stackoverflow.com/q/31744305/995714), [Bit-shifting unsigned longs in C](https://stackoverflow.com/q/62388255/995714) – phuclv Jun 18 '21 at 04:21
  • @Igor It's not a compiler error. It should be a **warning**, unless you've set "warnings as errors" so the compiler will report that as an error – phuclv Jun 18 '21 at 06:02
  • Make sure the RHS uses `unsigned long long` math: `bigvalue |= (codeword[3] & 0XFFFFull) << 46;` – chux - Reinstate Monica Jun 18 '21 at 12:20
  • there are lots of duplicates confirming that's a warning: [warning: left shift count >= width of type](https://stackoverflow.com/q/4201301/995714), [gcc 7.2: warning: left shift count >= width of type](https://stackoverflow.com/q/47872709/995714), [right shift count >= width of type or left shift count >= width of type](https://stackoverflow.com/q/39720691/995714), [warning: left shift count >= width of type \[enabled by default\]](https://stackoverflow.com/q/24356935/995714) – phuclv Jun 18 '21 at 13:45
  • @phuclv, we do have `-Werror` in there to make all dissenters we use compile cleanly. So, it is an error (at least to me). And so I'm treating it as such. – Igor Jun 18 '21 at 16:04
  • so it's nothing different from the other questions. The root cause is just due to the wrong type in the shift operation. The warnings means there may be UB happening, and once UB occurs anything can happen including a wrong result being output – phuclv Jun 18 '21 at 16:13

2 Answers2

1

For an expression like bigvalue |= (codeword[3] & 0XFFFF) << 46;; C would start by looking at (codeword[3] & 0XFFFF) and promoting it to unsigned int (likely 32 bits); then it would try to shift this intermediate unsigned int left by 46 (and complain that the shift count is too large for a "likely 32-bit" unsigned int).

To fix this you can tell C to promote the intermediate value to a larger size. E.g.:

    bigvalue |= (long long unsigned int)(codeword[3] & 0XFFFF) << 46;

Note that you could also use 0xFFFFULL as the mask instead; but if codeword[3] is already an unsigned 16-bit integer that mask won't actually do anything useful and could be deleted. E.g.:

    bigvalue |= (long long unsigned int)codeword[3] << 46;
Brendan
  • 35,656
  • 2
  • 39
  • 66
  • I gave a little more context to the question. The code was written a long time ago, but I think was rarely tested, until now with this specific scenario. – Igor Jun 18 '21 at 05:29
  • 1
    `codeword[3]` will be converted, not promoted, to `unsigned int`. Promotions are the particular conversions that apply to single values considered in isolation, and they never change the value. The conversion to `unsigned int` to match `0xFFFF` is part of the *usual arithmetic conversions*, and those may change values, as when a signed type is converted to unsigned. – Eric Postpischil Jun 18 '21 at 09:00
0

I guess guint16 is 16-bit width, then it supposedly can't be left-shifted for 30 and 46 bits, or at least results in just zero.

user26742873
  • 919
  • 6
  • 21
  • this is completely wrong, if `int` contains 64 bits then obviously `guint16` can be shifted by 46 without problem. And shifting more than the bitwidth often doesn't result in zero in most modern architectures because only the low 6 bits of the shift count will be considered. In C it's undefined behavior – phuclv Jun 18 '21 at 06:03
  • @phuclv Seems there is a misunderstanding: I guess `guint16` is 16-bit width, not 64-bit width like `int`. – user26742873 Jun 18 '21 at 07:30
  • 1
    of course I'm assuming `guint16` has 16 bits, but it'll be promoted to int, and if `int` has 64 bits then nothing special will happen. UB only happens when int has less than 46 bits. C doesn't say specific sizes of types, and `int` is only required to have at least 16 bits – phuclv Jun 18 '21 at 13:40