# HIWORD and LOWORD macros

• 12-05-2008
kalevi
HIWORD and LOWORD macros
I have seen the HIWORD and LOWORD in some winapi header file. As their name suggests they select the higher or lower WORD (16bit) from a DWORD(32bit). Whats the function of the '& 0xFFFF' in the definition of the HIWORD macro? I know what it does, but for me, it seems pointless. The right shift leaves 0s in the higher 16bits anyway, so whats the point in masking them out?

Simple test program:
Code:

```#include <stdio.h> typedef unsigned long DWORD; typedef unsigned short WORD; #define LOWORD(a) ((WORD)(a)) #define HIWORD(a) ((WORD)(((DWORD)(a) >> 16) & 0xFFFF)) int main() {         DWORD d=0xABCD1234;         printf("Original value:\n");         printf("      d  == %X\n",d);         printf("\nMacros:\n");         printf("LOWORD(d) == %X\n", LOWORD(d));         printf("HIWORD(d) == %X\n", HIWORD(d));         printf("\nSimple hiword:\n");         printf("  d >> 16 == %X\n", d >> 16);                         return 0; }```
• 12-05-2008
tabstop
Because the right shift may or may not leave zeroes. Try shifting -1 >> 16 and see what happens.
• 12-05-2008
kalevi
...
As I understand right shift does sign extension, thus signed negative numbers leave 1s, signed positive and unsigned numbers leave 0s in the upper bits.

Some test code:
Code:

```#include <stdio.h> typedef unsigned long DWORD; typedef unsigned short WORD; #define LOWORD(a) ((WORD)(a)) #define HIWORD(a) ((WORD)(((DWORD)(a) >> 16) & 0xFFFF)) int main() {         int a=-1; // signed numbers are stored in two's complement, so this equals 0xFFFFFFFF         printf("a >> 16            == &#37;X\n",a >> 16); // FFFFFFFF         printf("(DWORD)(a) >> 16  == %X\n",(DWORD)(a) >> 16); //FFFF         printf("\n");                         a=0xABCD1234;         //upper bits are sign extended -> int a : signed         printf("a >> 16            == %X\n",a >> 16); // FFFFABCD                 //no sign extension -> (DWORD) is an unsigned cast         printf("(DWORD)(a) >> 16  == %X\n",(DWORD)(a) >> 16); //ABCD         return 0; }```
For me it seems that there is still no need for a mask, because there is an unsigned cast in the macro definition: (DWORD)(a). So, why the need for the mask '& 0xFFFF' when we already have an unsigned cast?
• 12-05-2008
tabstop
I didn't notice the cast. So someone was probably just being paranoid.
• 12-05-2008
kalevi
Its good to know I don't miss anything there. Thanks for the help!
• 12-06-2008
Elysia
Or they wanted to be sure that they could stuff that into a WORD without warnings.
• 12-06-2008
matsp
Also, if you use the and at the end of such an operation, most optimizing compilers will "know" if it actually needs to perform the and operation or not - and thus it's not actually causing a problem to perform the and when it's not needed. If you then port the code to a machine which can't do this without using an and, it will still work.

Just because something works with one or two compilers on one or two types of machine, doesn't necessarily mean that it will work in ALL compilers or ALL processor architectures. Belts and braces.

--
Mats
• 12-06-2008
kalevi
So, the AND part makes the macro more robust. By the way, -out of curiosity- do you know cases (arch/os/compiler) where the code without the '& 0xffff' would not work?

Furthermore, how should I code in a platform/compiler independent manner? Any guide, book or tutorial on that?

Thanks for the useful comments!
• 12-07-2008
matsp
Quote:

Originally Posted by kalevi
So, the AND part makes the macro more robust. By the way, -out of curiosity- do you know cases (arch/os/compiler) where the code without the '& 0xffff' would not work?

Furthermore, how should I code in a platform/compiler independent manner? Any guide, book or tutorial on that?

Thanks for the useful comments!

The code as it is seems right. I don't see any reason to change it. I've not worked on any system where the cast to a smaller time would perform an operation corresponding to the AND (either explicitly as an and, or some other operation that has the same effect). However, the C standard explicitly says that the result, if the receiving type on the left can not fit the entire result from the right, then it is undefined. It may be obscure and strange machines that this statement in the standard is there for - but it wouldn't be in the standard if the standards committee didn't think it was at least likely, if not true, that such machines would at some point in time exist (past, present or future). All the standards definitions are thought out for some reason - they don't just say "Oh, well, it's too hard to define this, let's just make it undefined". Rather someone comes up with a definition, and then the representative of some company that produces a compiler, or a processor manufacturer says "Well, that would break on our design, can we make it undefined under <some> circumstances". This ensures that a compiler CAN be produced for all architectures (at least the ones that are relevant).

Of course, if you KNOW that the compiler will do the right thing without the and, then you may omit the AND operation. But you will also have to trust the compiler to not "break" this behaviour (and the standard does allow it to break!) in the future.

But as I said earlier, I'm convinced that this type of operation can be optimized away by most modern compilers in most cases where it would occur - because it's not an unusual pattern, so the compiler would have a special case to deal with this sort of thing.

We sometimes get a bit too caught up in standards and undefined behaviour here, but having worked with many differnet compilers, I do KNOW that there are situations where the compiler implementor will "choose" between different solutions that are all within the standard - and if your work involves combining the result of two compilers, then it DOES sometimes get you into trouble when these things are cropping up. Not to mention that sometimes the choice changes from one compiler version to another.

--
Mats