Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Should a cast be used to truncate a long variable?

I have a 16 bits unsigned variable. I need to split it in 8 bits chunks.

Is doing the following enough:

chunk_lsb = (uint8)variable;
chunk_msb = (uint8)(variable >> 8);

Or should I use a mask:

chunk_lsb = (uint8)(variable & 0xFFu);
chunk_msb = (uint8)((variable >> 8) & 0xFFu);

I know that both approaches work, I'm just looking for the best way to do it, if there is one. Maybe there's none and just use the cast to reduce calculations is the best way? What do you guys think?

like image 580
Soyding Mete Avatar asked Feb 25 '19 12:02

Soyding Mete


1 Answers

It isn't clear what type variable is. Without that specified, we can only speculate.

But in general, you should avoid bit shifting on signed integer types, as that leads to various forms of poorly-defined behavior. This in turn means that you have to be careful with small integer types too, because they get promoted to signed int. See Implicit type promotion rules.

The specific case of (uint8)((variable >> 8) & 0xFFu); is safe if variable is unsigned. Otherwise it is unsafe, since right-shifting a negative value leads to implementation-defined behavior (arithmetic or logical shift).

variable << 8 will invoke undefined behavior on 16 bit systems in case variable is a small integer type, or an int16_t.

The safest, most portable way no matter left/right shift is therefore this:

chunk_lsb = variable;
chunk_msb = ((unsigned int)variable >> 8);

Though you might want to be overly explicit in order to silence all compiler warnings:

chunk_lsb = (uint8_t) (variable & 0xFFu);
chunk_msb = (uint8_t) ( (unsigned int)variable>>8 & 0xFFu );
like image 100
Lundin Avatar answered Oct 27 '22 17:10

Lundin