4

Lets say I want to store the low 16 bits of a uint32_t in a uint16_t on windows, I could do it either

uint32_t value = 123456789;
uint16_t low1 = value; //like this
uint16_t low2 = value & 0xFFFF; //or this

There appears to be no difference in the results but I couldn't find any documentation explicitly stating that this is defined behavior. Could it be different under circumstances X or Y? Or is this just how it works?

user81993
  • 6,167
  • 6
  • 32
  • 64
  • Possible duplicate of [What happens when I assign long int to int in C?](http://stackoverflow.com/questions/13652556/what-happens-when-i-assign-long-int-to-int-in-c) – phuclv Mar 26 '16 at 10:18
  • 2
    the high bits are always truncated, no need to mask – phuclv Mar 26 '16 at 10:19
  • [When an int is cast to a short and truncated, how is the new value determined](http://stackoverflow.com/q/34885966/995714) – phuclv Mar 26 '16 at 10:25
  • @LưuVĩnhPhúc: The question you link to concerns signed integers. This question is about unsigned integers. The rules are different. – Cheers and hth. - Alf Mar 26 '16 at 10:28

2 Answers2

2

The C++ standard guarantees that assignment to and initialization of unsigned types gives you the value modulo 2n, where n is the number of bits in the value representation of the unsigned type.

In Windows all bits participate in the value representation.

Hence using a bitmask serves no purpose other than to put a little stumbling block in the way for the future, when one might change the types.


If you absolutely want to use a mask, e.g. to avoid a compilation warning from an over-zealous compiler, then you can do it in a type-independent way like this, assuming that the type is unsigned:

uint16_t low2 = value & uint16_t(-1);

Which relies on the aforementioned modulo-2n guarantee.

Cheers and hth. - Alf
  • 142,714
  • 15
  • 209
  • 331
  • 2
    Isn't it better to use `~0` for the mask? `-1` is not a valid value for an unsigned int and might not produce the correct bit mask for all systems (e.g. embedded systems without two complement). – Rocki Mar 26 '16 at 15:45
  • @Rocki: The code is valid, *for the reasons stated*. And contrary to your impression (where on Earth did you get it) it always produces the correct mask, since it is of the correct type. `~0`, on the other hand, is of incorrect type `int`. – Cheers and hth. - Alf Mar 26 '16 at 18:52
  • @Alf I meant `uint16_t low2 = value & uint16_t(~0);`. Today almost all computers use two's complement and your assumption that -1 produce the correct bit mask is correct, but imagine a architecture with ones' complement where `uint16_t(-1)` leads to the bit mask `1111 1111 1111 1110`. – Rocki Mar 26 '16 at 20:40
  • @Rocki: There is no dependency on architecture: the result is guaranteed by the C++ standard. As stated in the answer. – Cheers and hth. - Alf Mar 26 '16 at 20:44
0

The compiler should give you a warning, that value will be truncated if you use -Wconversion.

warning: conversion to 'uint16_t {aka short unsigned int}' from 'uint32_t {aka unsigned int}' may alter its value [-Wconversion]
uint16_t low1 = value;
                  ^

With bitmask g++ do not produce a warning...

Rocki
  • 363
  • 1
  • 2
  • 7