While looking at various sdks it seems LOBYTE and HIBYTE are rarely consistent as shown below.
Windows
#define LOBYTE(w) ((BYTE)(((DWORD_PTR)(w)) & 0xff))
#define HIBYTE(w) ((BYTE)((((DWORD_PTR)(w)) >> 8) & 0xff))
Various Linux Headers
#define HIBYTE(w) ((u8)(((u16)(w) >> 8) & 0xff))
#define LOBYTE(w) ((u8)(w))
Why is & 0xff needed if it's cast to a u8? Why wouldn't the following be the way to go? (assuming uint8_t and uint16_t are defined)
#define HIBYTE(w) ((uint8_t)(((uint16_t)(w) >> 8)))
#define LOBYTE(w) ((uint8_t)(w))
From ISO/IEC 9899:TC3, 6.3.1.3 Signed and unsigned integers (under 6.3 Conversions):
While that sounds a little convoluted, it answers the following question.
It is not needed, because the cast does the masking automatically.
When it comes to the question in the topic, the OP's last suggestion is:
That will work as expected for all unsigned values. Signed values will always be converted to unsigned values by the macros, which in the case of two's complement will not change the representation, so the results of the calculations are well defined. Assuming two's complement, however, is not portable, so the solution is not strictly portable for signed integers.
Implementing a portable solution for signed integers would be quite difficult, and one could even question the meaning of such an implementation:
>>
for negative values, for instance, is implementation-defined, so getting a portable well-defined "high byte" sounds challenging. One should really question the purpose of such a calculation.And since we are playing language lawyer, we might want to wonder about the signedness of the left operand of
(uint16_t)(w) >> 8
. Unsigned could seem as the obvious answer, but it is not, because of the integer promotion rules.Integer promotion applies, among others, to objects or expressions specified as follows.
The integer promotion rule in such a case is specified as:
That will be the case for the left operand on a typical 32-bit or 64-bit machine.
Fortunately in such a case, the left operand after conversion will still be nonnegative, which makes the result of
>>
well defined: