Condividi tramite


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.