2013-05-21 8 views
7

Io non riesco a capire ciò che questo significa macro:Qual è il significato di questa macro C++?

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

DECLARE_HANDLE(HWND); 

ho imparato dal programma C che:

"##" significa collegare il parametro.

così la macro uguale:

typedef struct HWND__{int i;}*HWND 

è questo diritto?

Se è giusto, qual è il significato di quella frase?

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

codice da un gioco Bombermaaan (per Windows e Linux),
collegamento http://sourceforge.net/p/bombermaaan/code/HEAD/tree/trunk/src/Bombermaaan/winreplace.h,
linea No 90.

+0

cosa significa? #define INVALID_SOCKET (SOCKET) (~ 0) – riqitang

+1

'~' è l'operatore * logico not *, che in questo caso ripristinerà tutti i bit del numero in cui è stato inserito 0. 'char sock = INVALID_SOCKET;' will be 0xFF, 'int sock = INVALID_SOCKET' sarà 0xFFFFFFFF. – Gui13

+0

grazie a @Sean per porre la domanda, una buona domanda. e grazie Xgbi per la tua risposta molto dettagliata. – puwei219

risposta

10

Lo scopo principale di questo costrutto è impedire l'uso improprio delle maniglie.Se tutte le maniglie sono semplicemente void * oppure int o long long o qualche altro tipo di base, non c'è nulla che impedisca di usarne una invece di un'altra. Un puntatore a un struct HWND__ e puntatore a struct HBITMAP__ non è la stessa cosa, quindi se avete un il seguente codice:

HWND hwnd; 
HBITMAP hbmp; 

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

E 'una tecnica abbastanza classico per garantire che si ottiene tipi unici di qualcosa che il fornitore API non voglio fornire la vera dichiarazione per. Anche se non sono del tutto sicuro perché hanno nemmeno bisogno di una dichiarazione struct corretta, probabilmente si potrebbe ottenere via con:

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

che sarà anche garantire che qualsiasi dereferece HWND non sarà possibile, dal momento che il compilatore opporsi a "uso di tipo incompleto".

+0

È un * po '* fastidioso se si desidera utilizzare un puntatore intelligente per pulire comunque, e non sono sicuro che tenere un decltype (* std :: declval ()>) 'sia sicuro (stavo per chiederlo a volte). Ciò lo rende una bella classe di 'Handle' RAII. Tieni presente che 'STRICT' ha un ruolo anche qui. – chris

+0

@Chris: Probabilmente un'idea migliore per avvolgere l'intera gestione di HWND in una classe che crea l'oggetto finestra, lo gestisce e quindi alla distruzione lo chiude. –

+0

Bene, Windows è un po 'schizzinoso (non vuoi acquisire la finestra di qualcun altro e farlo fare per te), "HWND" è solo la prima maniglia che mi viene in mente.Il mio piano era di creare una pura classe 'Handle' per tenere l'handle e ripulire con la funzione fornita dall'utente e di avere classi reali che rappresentassero questi oggetti e che possano usare la classe' Handle' per gestire la risorsa più facilmente. In un mondo ideale, l'utente non dovrebbe sapere che esiste la classe 'Handle'. – chris

0

Definisce un HWND come puntatore a struct HWND__ che contiene int i.

Quindi, ora è possibile utilizzare nel codice il tipo HWND.

+0

grazie per la tua gentilezza per la spiegazione del significato del codice. – puwei219

1

Esattamente.

Viene utilizzato per dichiarare un puntatore opaco a una struttura sconosciuta.

Non so perché non hanno semplicemente dichiarano come un

typedef void* HWND; 

Probabilmente per problemi di allineamento, dal momento che le strutture possono essere allineati, ma non tipi fondamentali.
Come accennato in precedenza, la dichiarazione del tipo come struttura consente un controllo del tipo in fase di compilazione.
Intelligente!

+0

non ora perché usare il formato complesso, o ... – puwei219

+0

Principalmente è così che usi HWND dove vuoi HWND, e HBITMAP dove vuoi HBITMAP, ecc. Se sono solo "void *", puoi fare 'HWND h = CreateBitmap (...);'. –

+0

Come indicato da Mats, void * non consente il controllo ortografico (i tipi di handle diversi possono essere mescolati). Tuttavia, non capisco perché non semplicemente #define DECLARE_HANDLE (n) typedef struct n ## __ * n; (senza una vera definizione di struttura) che fornirebbe vera opacità e impedirebbe qualcosa come ++ myhandle. – user396672

4

L'assunzione è corretta.

È possibile controllare questo con il seguente codice di prova semplice.

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; 
0

DECLARE_HANDLE(HWND); espande infatti quello di

typedef struct HWND__{int i;}*HWND; 

Ora, si sta chiedendo che cosa significa? Basta dividere il typedef in due fasi:

struct HWND__ 
{ 
    int i; 
}; 

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

Così, si definisce una struttura HWND__ contenente un int (denominato i) e dichiara un tipo alias HWND come puntatore HWND__.