I am reading an uint16 from a sensor connected to an raspberry (arm). I convert the data from little endian to big endian via:
// result = 0A 0B
// 0B 00 | 00 0A
(result << 8) | (result >> 8);
So 0A 0B is 0B 0A afterwards.
But I also saw people using this:
(result << 8) + (result >> 8);
Is there any advantage of using the addition? My guess is, there is no really advantage, it is just a bit slower.
There is a big difference when it comes to sum two numbers for example:
EF10 = 0FF0 + 00FF != 0FF0 | 00FF = 0FFF
Maybe I answered my own question already but it would be nice, if someone could evaluate. Would not be the first time I am tricking myself.
There is no difference (or advantage, at least not on modern processors) if the bits being combined aren't overlapping (in other words, the mask on the left-hand side has zeros for all bits set by the right-hand side, and vice versa)
The code shown here:
// result = 0A0B0C0D 0E0F0A0B
// 0E0F0A0B 00000000 | 00000000 0A0B0C0D
((result << 8) & 0xFF00) | (result >> 8);
is a little confusing - the comment seems to imply that it's a 32-bit value, but the calculation implies a 16-bit result
You will get different results for example if you do something like this:
value |= 128;
vs
value += 128;
when value
already has the bit 7 set.
Note that at least in clang:
#include <cstdint>
uint32_t func1(uint32_t x)
{
return (x >> 8) | ((x << 8) & 0xFF000000);
}
uint32_t func2(uint32_t x)
{
return (x >> 8) + ((x << 8) & 0xFF000000);
}
The exact same code is generated:
_Z5func1j: # @_Z5func1j
movl %edi, %eax
shrl $8, %eax
shll $8, %edi
andl $-16777216, %edi # imm = 0xFFFFFFFFFF000000
leal (%rdi,%rax), %eax
retq
_Z5func2j: # @_Z5func2j
movl %edi, %eax
shrl $8, %eax
shll $8, %edi
andl $-16777216, %edi # imm = 0xFFFFFFFFFF000000
leal (%rdi,%rax), %eax
retq
Using bitwise or |
makes it clear what is the intention to who reads the code, and that's the important point.
I would be surprised of speed differences between the two approaches.
Even better would be:
x = (x << 8) | (x >> 8);
because there is no need mask the left part (as incoming bits are zeros).
In case of a signed integer instead what is coming in when performing a right-shift operation on negative values is implementation dependent, therefore portable code should use
x = (x << 8) | ((x >> 8) & 0xFF);
to make it clear that a byte-swap operation is requested.