Should I use a bit mask when truncating uint64_t to uint8_t[i]?

If I have a large int, say a uint64_t, and an array of uint8_t, e.g.:

uint64_t large = 12345678901234567890;
uint8_t small[5];

and I want to copy the 8 least significant bits of the uint64_t into an element of the array of uint8_t, is it safe to just use:

small[3] = large;

or should I use a bit-mask:

small[3] = large & 255;

i.e. Is there any situation where the rest of the large int may somehow overflow into the other elements of the array?

Upvotes: 8

Views: 2424

Answers (2)

Barry
Barry

Reputation: 303890

This is perfectly safe:

small[3] = large;

and such a conversion is explicitly described in [conv.integral]:

If the destination type is unsigned, the resulting value is the least unsigned integer congruent to the source integer (modulo 2n where n is the number of bits used to represent the unsigned type).

That is, these four statements all are guaranteed to end up with the same value in small[3]:

small[3] = large;
small[3] = large % 256;
small[3] = large & 255;
small[3] = static_cast<uint8_t>(large);

there's no functional reason to do the % or & or cast yourself, though if you want to anyway I would be surprised if the compiler didn't generate the same code for all four (gcc and clang do).

The one difference would be if you compile with something like -Wconversion, which would cause this to issue a warning (which can sometimes be beneficial). In that case, you'll want to do the cast.

Upvotes: 3

bytecode77
bytecode77

Reputation: 14860

It will most certainly not cause data to be processed incorrectly. However, some compilers may generate a warning message.

There are two options to avoid these.

You can cast your variable:

(uint8_t)large

Or you can disable the warning:

#pragma warning(disable:4503)

I would suggest casting the variable, because hiding compiler warnings will potentially keep you from spotting actual problems and is therefore not best practice.

Upvotes: 5

Related Questions