c++cwindowswinapivisual-c++

Why is INVALID_HANDLE_VALUE defined via double cast?


MS defines INVALID_HANDLE_VALUE as follows (Windows SDK, handleapi.h):

#define INVALID_HANDLE_VALUE ((HANDLE)(LONG_PTR)-1)

Why do they do this with a double cast - first to LONG_PTR (alias __int64 alias long long on 64bit resp. long on 32bit), and second HANDLE (alias void*), why not just:

#define INVALID_HANDLE_VALUE ((HANDLE)-1)

I assume a meaning but do not see it.


Solution

  • I believe it was done for avoiding a MSVC compiler warning on 64 bit targets (assuming MSVC is the main compiler MS had in mind for Windows environment).

    Casting a 32 bit signed integer to a 64 bit pointer type triggers warning C4312:

    This warning detects an attempt to assign a 32-bit value to a 64-bit pointer type, for example, casting a 32-bit int or long to a 64-bit pointer.

    This can be an unsafe conversion even for pointer values that fit in 32 bits when sign extension occurs. If a negative 32-bit integer is assigned to a 64-bit pointer type, sign extension causes the pointer value to reference a memory address different from the value of the integer.

    This warning is only issued for 64-bit compilation targets.

    Example:

    int i = -1;
    void * p = (void*)i;
    

    Triggers:

    warning C4312: 'type cast': conversion from 'int' to 'void *' of greater size
    

    Live demo 1

    Adding the cast to long long before the cast to the void* solves this warning because now the final cast to a pointer type is of a 64 bit value:

    int i = -1;
    void * p = (void*)(long long)i;
    

    Live demo 2.


    Update:
    As the OP commented below, when using an int literal of -1 instead of a variable, the MSVC compiler does not issue a warning:

    void * p = (void*)-1;
    

    (see demo).

    My guess is that the new MSVC is smart enough to see that the cast is in fact safe, whereas older versions of the compiler issued the warning based on the type of the literal only (which is int).
    If my guess is correct, the final answer to the question is that the double cast is in fact there because of historic reasons (when the compiler was issueing the said warning based on the type of the literal).

    Final note:
    The reason could also be related to support on other compilers.
    Interestingly, current gcc and clang also issue a similat warning when a variable is used (demo), but not when a literal is used (demo). So again it is a matter of historic reasons.