9

I am trying to understand, what would be the best way to define BYTE, WORD and DWORD macros, which are mentioned in answers of this question.

#define LOWORD(l) ((WORD)(l))
#define HIWORD(l) ((WORD)(((DWORD)(l) >> 16) & 0xFFFF))
#define LOBYTE(w) ((BYTE)(w))
#define HIBYTE(w) ((BYTE)(((WORD)(w) >> 8) & 0xFF))

Would it be correct to assume, that:

  • BYTE is macro defined as #define BYTE __uint8_t
  • WORD is macro defined as #define WORD __uint16_t
  • DWORD is macro defined as #define DWORD __uint32_t

If yes, why cast to another macro instead of casting to __uint8_t, __uint16_t or __uint32_t? Is it written like that to increase clarity?

I also found another question which answers include typedef, with little bit more of research I've found answers to question about comparing #define and typedef. Would typedef be better to use in this case?

Ardent Coder
  • 3,777
  • 9
  • 27
  • 53
Lycopersicum
  • 529
  • 1
  • 6
  • 17
  • 1
    You can do what you like. They’re names used on Windows. The names like `__uint8_t` are wholly non-standard. Whether they do what you want is at the whim of the compiler. – Jonathan Leffler Dec 07 '17 at 15:06
  • 3
    Instead of using __uint8_t, __uint16_t or __uint32_t you may include `stdint.h` and use uint8_t, uint16_t or uint32_t which [conform the standard](http://en.cppreference.com/w/c/types/integer). – Innokentiy Alaytsev Dec 07 '17 at 15:08
  • 2
    These are typedefs from the Windows SDK, they isolate the winapi from the C compiler implementation and processor architecture. Your #defines look fine. The macros you posted are simple crackers to lift an 8-bit or 16-bit value from a larger integral type, SendMessage() in particular requires a lot of crunching to fit message arguments in the two parameters it takes. The kind of economy that mattered 30 years ago when they had to shoehorn a GUI into a quarter megabyte of memory. – Hans Passant Dec 07 '17 at 15:09
  • @JonathanLeffler but how about compilers like GNU GCC used in GNU/Linux environment? – Lycopersicum Dec 07 '17 at 15:10
  • @HansPassant, I couldn't mention two users in one comment, therefore I ask you to read my previous comment. – Lycopersicum Dec 07 '17 at 15:14
  • 1
    What about GCC? The double-underscore names are reserved for use by the implementation for any purpose. They are not mandated by any standard. What you have will work on a GCC (and Clang because it emulates GCC), but other compilers are not required to recognize the types. – Jonathan Leffler Dec 07 '17 at 15:14
  • I don't see the real question, maybe you just didn't try it yet. If you meant to target Windows with GCC then you should not write these yourself. Use MinGW-w64 instead. You'll at least need the link libraries it supplies, you get the macros for free with a standard #include. – Hans Passant Dec 07 '17 at 15:20
  • @HansPassant I was experimenting with [online C compiler](https://www.tutorialspoint.com/compile_c_online.php) and `BYTE` and others appeared as undefined, therefore I was interested, how that should be defined. – Lycopersicum Dec 07 '17 at 15:25

2 Answers2

11

This is a portable solution:

#include <stdint.h>

typedef uint32_t DWORD;   // DWORD = unsigned 32 bit value
typedef uint16_t WORD;    // WORD = unsigned 16 bit value
typedef uint8_t BYTE;     // BYTE = unsigned 8 bit value
Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
3

You have it defined at: https://msdn.microsoft.com/en-us/library/windows/desktop/aa383751(v=vs.85).aspx, and that is already defined in Windows Data Type headers for WinAPI:

typedef unsigned short WORD;
typedef unsigned char BYTE;
typedef unsigned long DWORD;

and it is a type, and not a macro.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
VladP
  • 529
  • 3
  • 15
  • 4
    Those typedefs won't necessarily be correct with other compilers (e.g. `DWORD` is assumed to be 32 bits but `unsigned long` may be larger on non-Microsoft compilers). – interjay Dec 07 '17 at 15:12