More specifically, why is the same thing typedef
'd with multiple different names in many cases, and why typedef
pointer types (obscuring logic at times)?
For example:
typedef const WCHAR *LPCWSTR, *PCWSTR;
What is the point of that?
The Windows API (application programming interface) allows user-written programs to interact with Windows, for example to display things on screen and get input from mouse and keyboard. All Windows programs except console programs must interact with the Windows API regardless of the language.
The typedef keyword allows the programmer to create new names for types such as int or, more commonly in C++, templated types--it literally stands for "type definition". Typedefs can be used both to provide more clarity to your code and to make it easier to make changes to the underlying data types that you use.
typedef is necessary for many template metaprogramming tasks -- whenever a class is treated as a "compile-time type function", a typedef is used as a "compile-time type value" to obtain the resulting type.
The following table contains the following types: character, integer, Boolean, pointer, and handle. The character, integer, and Boolean types are common to most C compilers.
There's actually a few different things going on here:
First the Near/Far pointers: Back in Win16 days, you had near and far pointers; near pointers were basically just 16 bits offsets, so could only refer to objects within 64k of an app's default data pointer (DS or Data Segment register), but they were small and fast; whereas a larger 'far pointer' or long pointer consisted of both segment and offset, so could refer to anything within the 1M address space. When the 386 came along, all this segment:offset business finally went away, and all pointers were just 32 bit addresses into flat 32bit address spaces. And that's why there's both P... and LP... versions.
Why bother with typedefs in the first place? It's just a convenience or shorthand: typing "LPSTR" is more convenient than "const char far *". But it also becomes a recognizable idiom: you see LPSTR and know straight away that it's how Windows deals with strings in its API.
There's also an abstraction going on here: Windows generally defines its own versions of types and uses them instead of the C versions. So Windows APIs use DWORD instead of int, or VOID instead of void. This was needed to plug some holes in C at the time - there was no bool, so introducing BOOL avoided having different APIs use different types to represent boolean values (eg char vs int). It also to some extent made the Windows API independent of an underlying C implementation: C doesn't require that int is a specific size: it could be 16 bits or 32 bits depending on the compiler. But for an OS API, its important to specify these things exactly. So rather than using int or long, Windows instead uses INT and LONG, which it then defines as needed, and typedefs to whatever underlying C type does the actual job.
Finally, some of these typedefs are actually hinting at specific usages beyond just type information. BOOL and INT are both typedef'd as int, but it's clear that an API parameter specified as BOOL is going to be used in a TRUE/FALSE sense, not as an integer value. (Remember that this predates the 'bool' type.) Likewise, BYTE - which is unsigned char - suggests that a parameter is actually going to be used as a 8-bit numberic value rather than as a alphanumeric or symbol character. And LPSTR indicates that the value is expected to be a NUL-terminated string, rather than just pointing to arbitrary char values. BSTR and LPWSTR have the same underlying typedef - they're both WCHAR * - but BSTRs have a length prefix and so must be allocated with the SysAllocString API, having a separate typedef here helps keep the two separate in code and document API requirements: if you see an API that takes a BSTR as a parameter, then you know that you can't just pass in a wide string, even though the underlying type is the same, there's additional requirements for that parameter.
The reason there is both PCWSTR and LPCWSTR is that in ancient times there was a difference. LPCWSTR used to be const WCHAR FAR *.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With