Errori comuni del compilatore
Questa sezione illustra gli errori tipici del compilatore che si verificano durante la migrazione di una codebase esistente. Questi esempi provengono dal codice HAL a livello di sistema, anche se i concetti sono direttamente applicabili al codice a livello di utente.
Avviso C4311 Esempio 1
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long
-
Codice
-
pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA;
-
Descrizione
-
PtrToUlong è una funzione o una macro inline, a seconda dell'utilizzo. Tronca un puntatore a una ULONG. Anche se i puntatori a 32 bit non sono interessati, la metà superiore di un puntatore a 64 bit viene troncata.
CIA_PCI_CONFIG_BAedizione Standard_QVA viene dichiarato come PVOID. Il cast di ULONG funziona nel mondo a 32 bit, ma genera un errore nel mondo a 64 bit. La soluzione consiste nell'ottenere un puntatore a 64 bit a ULONG, perché la modifica della definizione dell'unione definita da pPciAddr-u.AsULONG> nelle modifiche di codice è eccessiva.
L'utilizzo della macro PtrToUlong per convertire il valore PVOID a 64 bit nell'oggetto ULONG necessario è consentito perché sono disponibili informazioni sul valore specifico di CIA_PCI_CONFIG_BAedizione Standard_QVA. In questo caso, questo puntatore non avrà mai dati nei 32 bit superiori.
-
Soluzione
-
pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);
Avviso C4311 Esempio 2
'type cast': troncamento puntatore da 'struct _ERROR_FRAME *__ptr64 ' a 'unsigned long
-
Codice
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError );
-
Descrizione
-
Il problema è che l'ultimo parametro di questa funzione è un puntatore a una struttura di dati. Poiché PUncorrectableError è un puntatore, cambia le dimensioni con il modello di programmazione. Il prototipo per KeBugCheckEx è stato modificato in modo che l'ultimo parametro sia un ULONG_PTR. Di conseguenza, è necessario eseguire il cast del puntatore della funzione a un ULONG_PTR.
È possibile chiedere perché PVOID non è stato usato come ultimo parametro. A seconda del contesto della chiamata, l'ultimo parametro può essere diverso da un puntatore o ad esempio un codice di errore.
-
Soluzione
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );
Avviso C4244 Esempio 1
'=': conversione da 'struct _CONFIGURATION_COMPONENT *__ptr64 ' a 'struct _CONFIGURATION_COMPONENT *', possibile perdita di dati
-
Codice
-
Component = &CurrentEntry->ComponentEntry;
-
Descrizione
-
La funzione dichiara la variabile Component come PCONFIGURATION_COMPONENT. Successivamente, la variabile viene usata nell'assegnazione seguente che appare corretta:
Component = &CurrentEntry->ComponentEntry;
Tuttavia, il tipo PCONFIGURATION_COMPONENT è definito come:
typedef struct __CONFIGURATION_COMPONENT { ... ... } CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;
La definizione del tipo per PCONFIGURATION_COMPONENT fornisce un puntatore a 32 bit nei modelli a 32 bit e a 64 bit perché è dichiarato POINTER_32. La finestra di progettazione originale di questa struttura sapeva che sarebbe stata usata in un contesto a 32 bit nel BIOS ed espressamente definita per tale uso. Questo codice funziona correttamente in Windows a 32 bit perché i puntatori sono a 32 bit. In Windows a 64 bit non funziona perché il codice si trova nel contesto a 64 bit.
-
Soluzione
-
Per risolvere questo problema, usare CONFIGURATION_COMPONENT * anziché l'PCONFIGURATION_COMPONENT a 32 bit . È importante comprendere chiaramente lo scopo del codice. Se questo codice è destinato a toccare il BIOS a 32 bit o lo spazio di sistema, questa correzione non funzionerà.
POINTER_32 è definito in Ntdef.h e Winnt.h.
#ifdef (__AXP64__) #define POINTER_32 _ptr32 #else #define POINTER_32 #endif
Avviso C4242 Esempio 2
'=': conversione da '__int64 ' a 'unsigned long ', possibile perdita di dati
-
Codice
-
ARC_STATUS HalpCopyNVRamBuffer ( IN PCHAR NvDestPtr, IN PCHAR NvSrcPtr, IN ULONG Length ) { ULONG PageSelect1, ByteSelect1; ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK; ByteSelect1 = (NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
-
Descrizione
-
Questo avviso viene generato perché il calcolo usa valori a 64 bit, in questo caso puntatori e posiziona il risultato in una ULONG a 32 bit.
-
Soluzione
-
Digitare eseguire il cast del risultato del calcolo in una ULONG , come illustrato di seguito:
ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
Il typecasting del risultato consente al compilatore di conoscere il risultato. Detto questo, assicurati di comprendere il calcolo e di essere sicuri che si adatti a una ULONG a 32 bit.
Se il risultato potrebbe non rientrare in una ULONG a 32 bit, modificare il tipo di base della variabile che conterrà il risultato.
Avviso C4311 - Esempio 1
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long'
-
Codice
-
ULONG HalpMapDebugPort( IN ULONG ComPort, OUT PULONG ReadQva, OUT PULONG WriteQva) { ULONG ComPortAddress; ULONG PortQva; // Compute the port address, based on the desired com port. switch( ComPort ){ case 1: ComPortAddress = COM1_ISA_PORT_ADDRESS; break; case 2: default: ComPortAddress = COM2_ISA_PORT_ADDRESS; } PortQva = (ULONG)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress; // Return the QVAs for read and write access. *ReadQva = PortQva; *WriteQva = PortQva; return ComPortAddress; }
-
Descrizione
-
Questa intera funzione gestisce gli indirizzi come numeri interi, richiedendo la necessità di digitare tali interi in modo portabile. Tutte le variabili locali, i valori intermedi nei calcoli e i valori restituiti devono essere tipi portabili.
-
Soluzione
-
ULONG_PTR HalpMapDebugPort( IN ULONG ComPort, OUT PULONG_PTR ReadQva, OUT PULONG_PTR WriteQva) { ULONG_PTR ComPortAddress; ULONG_PTR PortQva; // Compute the port address, based on the desired com port. switch( ComPort ){ case 1: ComPortAddress = COM1_ISA_PORT_ADDRESS; break; case 2: default: ComPortAddress = COM2_ISA_PORT_ADDRESS; } PortQva = (ULONG_PTR)HAL_MAKE_QVA(CIA_PCI_SPARSE_IO_PHYSICAL) + ComPortAddress; // Return the QVAs for read and write access. *ReadQva = PortQva; *WriteQva = PortQva; return ComPortAddress; }
PULONG_PTR è un puntatore a 32 bit per Windows a 32 bit e 64 bit per Windows a 64 bit. Punta a un intero senza segno, ULONG_PTR, ovvero a 32 bit per Windows a 32 bit e a 64 bit per Windows a 64 bit.
Avviso C4311 - Esempio 2
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long'
-
Codice
-
BOOLEAN HalpMapIoSpace ( VOID ) { PVOID PciIoSpaceBase; PciIoSpaceBase = HAL_MAKE_QVA( CIA_PCI_SPARSE_IO_PHYSICAL ); //Map base addresses in QVA space. HalpCMOSRamBase = (PVOID)((ULONG)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
-
Descrizione
-
Anche se tutti i valori QVA (Quasi Virtual Address) sono realmente valori a 32 bit in questa fase e si adattano a ULONG, è più coerente considerare tutti gli indirizzi come valori ULONG_PTR quando possibile.
Il puntatore PciIoSpaceBase contiene l'appliance virtuale di query creata nella macro HAL_MAKE_QVA. Questa macro restituisce un valore a 64 bit con i primi 32 bit impostati su zero in modo che la matematica funzioni. È sufficiente lasciare il codice per troncare il puntatore in una ULONG, ma questa procedura è sconsigliata per migliorare la gestibilità e la portabilità del codice. Ad esempio, il contenuto di un'appliance virtuale di query potrebbe cambiare in futuro per usare alcuni dei bit superiori a questo livello, interrompendo il codice.
-
Soluzione
-
Essere sicuri e usare ULONG_PTR per tutte le operazioni matematiche relative a indirizzi e puntatori.
HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
Avviso C4311 Esempio 3
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long'
-
Codice
-
PVOID HalDereferenceQva( PVOID Qva, INTERFACE_TYPE InterfaceType, ULONG BusNumber) if ( ((ULONG) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG)Qva << IO_BIT_SHIFT ) ); } else { return (Qva); }
-
Descrizione
-
Il compilatore avvisa dell'indirizzo degli operatori (&) e di spostamento sinistro (<<) se vengono applicati ai tipi di puntatore. Nel codice precedente Qva è un valore PVOID . È necessario eseguirne il cast a un tipo integer per eseguire la matematica. Poiché il codice deve essere portabile, usare ULONG_PTR anziché ULONG.
-
Soluzione
-
if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );
Avviso C4311 Esempio 4
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long'
-
Codice
-
TranslatedAddress->LowPart = (ULONG)HalCreateQva( *TranslatedAddress, va);
-
Descrizione
-
TranslatedAddress è un'unione simile alla seguente:
typedef union Struct { ULONG LowPart; LONG Highpart; } LONGLONG QuadPart; }
-
Soluzione
-
Conoscere il resto del codice in Highpart, è possibile selezionare una delle soluzioni illustrate di seguito.
TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );
La macro PtrToUlong tronca il puntatore restituito da HalCreateQva a 32 bit. Sappiamo che l'appliance virtuale di query restituita da HalCreateQva ha i 32 bit superiori impostati su zero e la riga di codice molto successiva imposta TranslatedAddress-Highpart> su zero.
Con cautela, è possibile usare quanto segue:
TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);
Questo esempio funziona: la macro HalCreateQva restituisce 64 bit, con i 32 bit superiori impostati su zero. Prestare attenzione a non lasciare i 32 bit superiori non definiti in un ambiente a 32 bit, che questa seconda soluzione può effettivamente eseguire.
Avviso C4311 Esempio 5
'type cast': troncamento del puntatore da 'void *__ptr64 ' a 'unsigned long'
-
Codice
-
VOID HalpCiaProgramDmaWindow( PWINDOW_CONTROL_REGISTERS WindowRegisters, PVOID MapRegisterBase ) { CIA_WBASE Wbase; Wbase.all = 0; Wbase.Wen = 1; Wbase.SgEn = 1; Wbase.Wbase = (ULONG)(WindowRegisters->WindowBase) >> 20;
-
Descrizione
-
WindowRegisters-WindowBase> è un puntatore e ora è a 64 bit. Il codice indica di spostare a destra questo valore a 20 bit. Il compilatore non consente di usare l'operatore di scorrimento a destra (>>) su un puntatore. È quindi necessario eseguirne il cast a un tipo di intero.
-
Soluzione
-
Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));
Il cast a un ULONG_PTR è solo quello di cui abbiamo bisogno. Il problema successivo è Wbase. Wbase è una ULONG e è a 32 bit. In questo caso, sappiamo che il puntatore a 64 bit WindowRegisters-WindowBase> è valido nei 32 bit inferiori anche dopo essere stato spostato. Questo usa la macro PtrToUlong accettabile, perché tronca il puntatore a 64 bit in una ULONG a 32 bit. Il cast PVOID è necessario perché PtrToUlong prevede un argomento puntatore. Quando si esamina il codice dell'assembler risultante, tutto questo cast di codice C diventa solo un quad di caricamento, spostamento a destra e archiviazione lungo.