views:

620

answers:

4

And if so, why some Win32 headers use it?

For instance:

BOOL APIENTRY VerQueryValueA( const LPVOID pBlock,
    LPSTR lpSubBlock,
    LPVOID * lplpBuffer,
    PUINT puLen
    );

A bit more elaboration: If the API never uses references (or any other C++-only constructs) but only pointers and values, what is the point of having const LPVOID vs. LPCVOID.

Should I treat every place I see const LPVOID as some place where the real meaning is LPCVOID? (and thus it is safe to add a cast)

Further clarification: It appears that const LPVOID pBlock was indeed a mistake in this case. Windows 2008 SDK replaces it to LPCVOID in VerQueryValue signature. Wine did so quite some time ago.

+1  A: 

These links contain some information that makes it easy to understand typedef better:

http://www.velocityreviews.com/forums/t289888-need-clarification-on-typedef-keyword.html http://www.codeproject.com/KB/cpp/complex_declarations.aspx#typedef

Vijay Mathew
+8  A: 

A typedef-name denotes a type, and not a sequence of tokens (as does a macro). In your case, LPVOID denotes the type also denoted by the token sequence void *. So the diagram looks like

// [...] is the type entity, which we cannot express directly.
LPVOID => [void *]

Semantically if you specify the type const LPVOID, you get the following diagram (the brackets around the specifiers mean "the type denoted by the specifier"):

// equivalent (think of "const [int]" and "[int] const"):
const LPVOID <=> LPVOID const =>  const [void *] <=> [void *] const  
                              =>  ["const qualified void-pointer"]

It's not the same thing as the token sequence const void * - because this one would not denote a const qualified pointer type, but rather a pointer to a const qualified type (the thing pointed to would be const).

Syntactically a parameter declaration has the following (simplified) form:

declaration-specifiers declarator

The declaration-specifiers in case of const void *p are const void - so the base-type of *p is a const qualified void, but the pointer itself is not qualified. In case of const LPVOID p however the declaration-specifiers specify a const qualified LPVOID - which means the pointer type itself is qualified, making the parameter declaration identical to void *const p.

Johannes Schaub - litb
Wait, now I am confused. const void* and void* const are NOT the same.
EFraim
@EFraim, the box around `void *` means that it is the type denoted by `LPVOID` - it doesn't mean that the text appears in the declaration.
Johannes Schaub - litb
Ah, OK, this diagram just made me confused.
EFraim
It's similar to the function pointer thingy. While you cannot write `void(*)() p;` you can indeed write `typedef void(*f)(); f p;`. It's `[void(*)()] p;` here.
Johannes Schaub - litb
int const and const int are actually two different things, an int constant means that once the value is assigned you cannot change it and is constant in other words the address of an int const is fixed. Whereas a const int is a readonly value and cannot be changed. IIRC there's an extensive mention about this in Peter Van der Linden's Expert C Programming Deep C secrets.
tommieb75
@tommieb75: Sounds much like someone got mixed up with Java finals.
EFraim
Edited the diagram to make more clear the immaterial nature of these entities.
Johannes Schaub - litb
tommieb75: `const int` and `int const` are 100% identical in C and C++, just like `const int*` and `int const*`.
Roger Pate
I see it like this: a "constant number" is the same as a "number constant", and a "pointer to a constant number" is the same as a "pointer to a number constant", but it's not the same as a "constant pointer to a number" or a "pointer constant to a number". (the latter two are the same, though).
Johannes Schaub - litb
A: 

LPVOID is far generic pointer, which is already long time the same as normal generic pointer (it was different on old 16bit platforms).

denisenkom
Which is OK, however has little to do with the topic of the question.
EFraim
A: 

void* const x = 0;

x = 0; // this line will not compile - u cannot change x, only what it points to

x->NonConstMethod(); // will compile

const void* y = 0;

y = 0; // this line will compile - u can change y, but not what it points to

y->NonConstMethod(); // will not compile

const void* const z = 0; // u cannot change z or what it points to

// btw, the type of the 'this' pointer is "ClassName* const this;"

MGC