Regole per l'uso di puntatori
La conversione del codice da compilare per Microsoft Windows a 32 e 64 bit è semplice. È sufficiente seguire alcune semplici regole sui puntatori di cast e usare i nuovi tipi di dati nel codice. Di seguito sono riportate le regole per la manipolazione del puntatore.
Non eseguire il cast dei puntatori a int, long, ULONG o DWORD.
Se è necessario eseguire il cast di un puntatore per testare alcuni bit, impostare o cancellare bit oppure modificare il relativo contenuto, usare il tipo UINT_PTR o INT_PTR . Questi tipi sono tipi integrali che si adattano alle dimensioni di un puntatore per Windows a 32 e a 64 bit ( ad esempio ULONG per Windows a 32 bit e _int64 per Windows a 64 bit). Si supponga, ad esempio, di convertire il codice seguente:
ImageBase = (PVOID)((ULONG)ImageBase | 1);
Come parte del processo di conversione, è necessario modificare il codice nel modo seguente:
ImageBase = (PVOID)((ULONG_PTR)ImageBase | 1);
Usare UINT_PTR e INT_PTR laddove appropriato (e se si è incerti se sono necessari, non c'è alcun danno nell'usarli solo nel caso). Non eseguire il cast dei puntatori ai tipi ULONG, LONG, INT, UINT o DWORD.
Si noti che HANDLE è definito come void*, pertanto il typecasting di un valore HANDLE su un valore ULONG per testare, impostare o cancellare i bit a 2 ordine basso è un errore in Windows a 64 bit.
Utilizzare la funzione PtrToLong o PtrToUlong per troncare i puntatori.
Se è necessario troncare un puntatore a un valore a 32 bit, usare la funzione PtrToLong o PtrToUlong (definita in Basetsd.h). Queste funzioni disabilitano l'avviso di troncamento del puntatore per la durata della chiamata.
Usare queste funzioni con attenzione. Dopo aver convertito una variabile puntatore usando una di queste funzioni, non usarla mai di nuovo come puntatore. Queste funzioni troncano i 32 bit superiori di un indirizzo, che in genere sono necessari per accedere alla memoria a cui originariamente fa riferimento il puntatore. L'uso di queste funzioni senza un'attenta considerazione comporterà la fragilità del codice.
Prestare attenzione quando si usano POINTER_32 valori nel codice che possono essere compilati come codice a 64 bit. Il compilatore segnalerà l'estensione del puntatore quando viene assegnato a un puntatore nativo nel codice a 64 bit, non estendendo il puntatore a zero.
Prestare attenzione quando si usano POINTER_64 valori nel codice che possono essere compilati come codice a 32 bit. Il compilatore firmerà l'estensione del puntatore nel codice a 32 bit, senza estendere il puntatore.
Prestare attenzione all'uso dei parametri OUT.
Si supponga, ad esempio, di avere una funzione definita come segue:
void func( OUT PULONG *PointerToUlong );
Non chiamare questa funzione come indicato di seguito.
ULONG ul; PULONG lp; func((PULONG *)&ul); lp = (PULONG)ul;
Usare invece la chiamata seguente.
PULONG lp; func(&lp);
Il typecasting &ul a PULONG* impedisce un errore del compilatore, ma la funzione scriverà un valore puntatore a 64 bit nella memoria in &ul. Questo codice funziona in Windows a 32 bit, ma causerà il danneggiamento dei dati in Windows a 64 bit e sarà sottile e difficile da individuare. La riga inferiore: non giocare trucchi con il codice C, semplice e semplice è migliore.
Prestare attenzione alle interfacce polimorfiche.
Non creare funzioni che accettano parametri DWORD per i dati polimorfici. Se i dati possono essere un puntatore o un valore integrale, usare il tipo UINT_PTR o PVOID .
Ad esempio, non creare una funzione che accetta una matrice di parametri di eccezione tipizzati come valori DWORD . La matrice deve essere una matrice di valori DWORD_PTR . Pertanto, gli elementi della matrice possono contenere indirizzi o valori integrali a 32 bit. La regola generale è che se il tipo originale è DWORD e deve essere di larghezza del puntatore, convertirlo in un valore DWORD_PTR . Ecco perché esistono tipi di precisione puntatore corrispondenti. Se si dispone di codice che usa DWORD, ULONG o altri tipi a 32 bit in modo polimorfico ,ovvero si vuole che il parametro o il membro della struttura contenga un indirizzo, usare UINT_PTR al posto del tipo corrente.
Usare le nuove funzioni della classe finestra.
Se sono presenti dati privati della finestra o della classe che contengono puntatori, il codice dovrà usare le nuove funzioni seguenti:
Queste funzioni possono essere usate sia in Windows a 32 che a 64 bit, ma sono necessarie in Windows a 64 bit. Prepararsi per la transizione usando queste funzioni ora.
Inoltre, è necessario accedere a puntatori o handle nei dati privati della classe usando le nuove funzioni in Windows a 64 bit. Per facilitare l'individuazione di questi casi, gli indici seguenti non sono definiti in Winuser.h durante una compilazione a 64 bit:
- GWL_WNDPROC
- GWL_HINSTANCE
- GWL_HWNDPARENT
- GWL_Uedizione Standard RDATA
Winuser.h definisce invece i nuovi indici seguenti:
- GWLP_WNDPROC
- GWLP_HINSTANCE
- GWLP_HWNDPARENT
- GWLP_Uedizione Standard RDATA
- GWLP_ID
Ad esempio, il codice seguente non viene compilato:
SetWindowLong(hWnd, GWL_WNDPROC, (LONG)MyWndProc);
Deve essere modificato nel modo seguente:
SetWindowLongPtr(hWnd, GWLP_WNDPROC, (LONG_PTR)MyWndProc);
Quando si imposta il membro cbWndExtra della struttura WNDCLASS , assicurarsi di riservare spazio sufficiente per i puntatori. Ad esempio, se si riservano byte sizeof(DWORD) per un valore del puntatore, riserva sizeof(DWORD_PTR) byte.
Accedere a tutti i dati di finestra e classe usando FIELD_OFFedizione Standard T.
È comune accedere ai dati delle finestre usando offset hardcoded. Questa tecnica non è portabile a Windows a 64 bit. Per rendere portabile il codice, accedere ai dati della finestra e della classe usando la macro FIELD_OFFedizione Standard T. Non presupporre che il secondo puntatore abbia un offset pari a 4.
I tipi LPARAM, WPARAM e LRESULT cambiano dimensione con la piattaforma.
Durante la compilazione di codice a 64 bit, questi tipi si espandono a 64 bit, perché in genere contengono puntatori o tipi integrali. Non combinare questi valori con valori DWORD, ULONG, UINT, INT, int o long . Esaminare come usare questi tipi e assicurarsi di non troncare inavvertitamente i valori.