2

I am reading some Windows API header files and I saw some code that I don't understand:

typedef void *HANDLE;

typedef HANDLE DPI_AWARENESS_CONTEXT;

#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)

What does it mean to subtract a value from a void * typedef?

sourcenouveau
  • 29,356
  • 35
  • 146
  • 243
  • 6
    I think it's a cast of (void*) -1, rather than minusing 1 from void* – 0RR Dec 30 '20 at 18:49
  • 1
    Let's say the`#define` wasn't there, then in the code `DPI_AWARENESS_CONTEXT` will be a pointer to some address. Now let's introduce the `#define`. In all the occurrence of `DPI_AWARENESS_CONTEXT` there will be a trailing `-1`. That in pointer arithmetic means the address right before. – anotherOne Dec 30 '20 at 18:55

2 Answers2

6

There's no subtraction going on - DPI_AWARENESS_CONTEXT_UNAWARE expands to the value of -1 cast as a void *. It appears that it's being used as a sentinel value for the DPI_AWARENESS_CONTEXT type (which is a typedef for HANDLE, which is a typedef for void *).

John Bode
  • 119,563
  • 19
  • 122
  • 198
5

It is a cast, not a subtraction.

typedef void *HANDLE;

Results in a symbol HANDLE that is equivalent to void *

Then in turn

typedef HANDLE DPI_AWARENESS_CONTEXT;

results in a new symbol DPI_AWARENESS_CONTEXT that is equivalent to void *

leading to the expression:

#define DPI_AWARENESS_CONTEXT_UNAWARE ((DPI_AWARENESS_CONTEXT)-1)

which is equivalent to:

#define DPI_AWARENESS_CONTEXT_UNAWARE ((void *)-1)

meaning that any instance of DPI_AWARENESS_CONTEXT_UNAWARE in source code expands to (void *) at compile-time.

As an aside - Here are the hows and whys:

(void *) -1 == (size_t) -1

which is 0xFFFFFFFF on 32 bit machines,
or 0xFFFFFFFFFFFFFFFF on 64 bit machines.

On twos complement implementations of each respective architecture, these values are equivalent to -1, making them useful as sentinel values in routines such as sbrk()) (memory allocation support), or specifying dots per inch (dpi) awareness context.

Note: The above statement is incorrect for ones complement systems, but as indicated by the answers in this post ones complement is rare, and not likely to be used in any recent large scale commercial environment.

ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Both addresses are valid, given the respective architectures. Neither address is the equivalent of `-1`, unless you assume 2s complement representation. Neither architecture mandates it, though Windows' ABI requires it. Lots of wrongs interleaved with rights still yields wrong. Sorry. – IInspectable Dec 31 '20 at 03:07
  • @IInspectable - LOL, no need to be sorry :) It would have been more correct for me to say _unlikely addresses_ rather than _invalid addresses_, but because _unlikely addresses_ did not add any value, I edited the point away. As for my assumption of twos complement, again, if debating the point, I think you would win as the world does still contain ones complement environments, albeit rare. I have also made an edit to address that point. Thanks for commenting, both points were valid, and needed to be corrected. – ryyker Dec 31 '20 at 21:31