puwei219
puwei219

Reputation: 567

What is the meaning of this C++ macro?

I can't figure out what this macro means:

#define DECLARE_HANDLE(n) typedef struct n##__{int i;}*n

DECLARE_HANDLE(HWND);

I have learned from the C program that:

"##" means connect the parameter.

so the macro equals:

typedef struct HWND__{int i;}*HWND

Is this right?

If it is right, what is the meaning of that sentence?

==================

Code from a game Bombermaaan (for Windows and Linux),
link http://sourceforge.net/p/bombermaaan/code/HEAD/tree/trunk/src/Bombermaaan/winreplace.h,
line No 90.

Upvotes: 9

Views: 2513

Answers (5)

Whoami
Whoami

Reputation: 14408

Your assumption is correct.

You can check this with the following simple test code.

DECLARE_HANDLE(HWND);
struct HWND__ s;
HWND p = (HWND) malloc(sizeof(struct HWND__));
s.i = 20;
p->i = 100;
cout << "i valueis " << s.i<<" and " << p->i <<endl;

Upvotes: 6

Gui13
Gui13

Reputation: 13551

Exactly.

This is used to declare an opaque pointer to a structure that is unknown to you.

I don't know why they didn't simply declare it as a

typedef void* HWND;

Probably for alignment issues, since structures can be aligned but not basic types.
As mentioned above, declaring the type as a structure permits some compile-time type checking.
Clever!

Upvotes: 2

Mats Petersson
Mats Petersson

Reputation: 129374

The main purpose of this construct is to prevent the misuse of handles. If all handles are simply void * or int or long long or some other basic type, there is nothing to prevent you from using one instead of another. A pointer to a struct HWND__ and pointer to struct HBITMAP__ isn't the same thing, so if you have a the following code:

HWND hwnd;
HBITMAP hbmp;

hbmp = GetBitmap(...);
hwnd = hbmp;    // gives compiler error. 

It's a fairly classic technique to ensure that you get unique types for something that the API supplier don't want to provide the true declaration for. Although I'm not entirely sure why they even need a proper struct declaration, you could probably get away with:

#define DECLARE_HANDLE(n) struct n ## __; struct n ## __ *n;

That will also ensure that any dereferece HWND won't be possible, since the compiler will object to "use of incomplete type".

Upvotes: 11

gx_
gx_

Reputation: 4760

DECLARE_HANDLE(HWND); indeed expands to

typedef struct HWND__{int i;}*HWND;

Now, you're asking what it means? Just split the typedef into two steps:

struct HWND__
{
    int i;
};

typedef HWND__* HWND;  // C++ only; for both C++ and C: typedef struct HWND__* HWND;

Thus, it defines a struct HWND__ containing an int (named i) and declares a type alias HWND as pointer to HWND__.

Upvotes: 1

Alex
Alex

Reputation: 10126

It defines a HWND as a pointer to struct HWND__ that contains int i.

So, now you can use in the code the type HWND.

Upvotes: 0

Related Questions