Compartir a través de


Errores comunes del compilador

En esta sección se muestran los errores típicos del compilador que se producen al migrar una base de código existente. Estos ejemplos proceden del código HAL de nivel de sistema, aunque los conceptos se aplican directamente al código de nivel de usuario.

Advertencia C4311 Ejemplo 1

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long

Código

pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA;

Description

PtrToUlong es una función o macro insertada, en función del uso. Trunca un puntero a un ULONG. Aunque los punteros de 32 bits no se ven afectados, la mitad superior de un puntero de 64 bits se trunca.

CIA_PCI_CONFIG_BASE_QVA se declara como PVOID. La conversión ULONG funciona en el mundo de 32 bits, pero produce un error en el mundo de 64 bits. La solución consiste en obtener un puntero de 64 bits a un ULONG, ya que el cambio de la definición de la unión que pPciAddr-u.AsULONG> se define en cambios demasiado código.

El uso de la macro PtrToUlong para convertir el PVOID de 64 bits en el ULONG necesario se permite porque tenemos conocimiento sobre el valor específico de CIA_PCI_CONFIG_BASE_QVA. En este caso, este puntero nunca tendrá datos en los 32 bits superiores.

Solución

pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);

Advertencia C4311 Ejemplo 2

'type cast': truncamiento del puntero de 'struct _ERROR_FRAME *__ptr64' a 'unsigned long

Código

KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError );

Description

El problema es que el último parámetro de esta función es un puntero a una estructura de datos. Dado que PUncorrectableError es un puntero, cambia el tamaño con el modelo de programación. Se cambió el prototipo de KeBugCheckEx para que el último parámetro sea un ULONG_PTR. Como resultado, es necesario convertir el puntero de función a un ULONG_PTR.

Puede preguntar por qué PVOID no se usó como último parámetro. Dependiendo del contexto de la llamada, el último parámetro puede ser algo distinto de un puntero o quizás un código de error.

Solución

KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );

Advertencia C4244 Ejemplo 1

'=': conversión de 'struct _CONFIGURATION_COMPONENT *__ptr64' a 'struct _CONFIGURATION_COMPONENT *', posible pérdida de datos

Código

Component = &CurrentEntry->ComponentEntry;

Description

La función declara la variable Component como un PCONFIGURATION_COMPONENT. Más adelante, la variable se usa en la siguiente asignación que aparece correcta:

Component = &CurrentEntry->ComponentEntry;

Sin embargo, el tipo PCONFIGURATION_COMPONENT se define como:

typedef struct __CONFIGURATION_COMPONENT {
...
...
} CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;

La definición de tipo para PCONFIGURATION_COMPONENT proporciona un puntero de 32 bits en modelos de 32 y 64 bits porque se declara POINTER_32. El diseñador original de esta estructura sabía que iba a usarse en un contexto de 32 bits en el BIOS y lo definió expresamente para ese uso. Este código funciona bien en Windows de 32 bits porque los punteros tienen un tamaño de 32 bits. En Windows de 64 bits, no funciona porque el código está en contexto de 64 bits.

Solución

Para solucionar este problema, use CONFIGURATION_COMPONENT * en lugar del PCONFIGURATION_COMPONENT de 32 bits . Es importante comprender claramente el propósito del código. Si este código está pensado para tocar el BIOS de 32 bits o el espacio del sistema, esta corrección no funcionará.

POINTER_32 se define en Ntdef.h y Winnt.h.

#ifdef (__AXP64__)
#define POINTER_32 _ptr32
#else
#define POINTER_32
#endif

Advertencia C4242 Ejemplo 2

'=' : conversión de '__int64' a 'unsigned long', posible pérdida de datos

Código

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;

Description

Esta advertencia se genera porque el cálculo usa valores de 64 bits, en este caso punteros y coloca el resultado en un ULONG de 32 bits.

Solución

Escriba convertir el resultado del cálculo en un ULONG como se muestra aquí:

ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;

La difusión de tipos del resultado permite al compilador saber que está seguro sobre el resultado. Dicho esto, asegúrese de que comprende el cálculo y realmente está seguro de que caberá en un ULONG de 32 bits.

Si el resultado no cabe en un ULONG de 32 bits, cambie el tipo base de la variable que contendrá el resultado.

Advertencia C4311: ejemplo 1

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long'

Código

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

Description

Esta función completa se ocupa de direcciones como enteros, lo que requiere la necesidad de escribir esos enteros de forma portátil. Todas las variables locales, los valores intermedios en los cálculos y los valores devueltos deben ser tipos portátiles.

Solución

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 es un puntero que es de 32 bits para Windows de 32 bits y 64 bits para Windows de 64 bits. Apunta a un entero sin signo, ULONG_PTR, que es de 32 bits para Windows de 32 bits y 64 bits para Windows de 64 bits.

Advertencia C4311: ejemplo 2

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long'

Código

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

Description

Aunque todos los valores de QVA (cuasi dirección virtual) son realmente valores de 32 bits en esta fase y caberán en un ULONG, es más coherente tratar todas las direcciones como valores de ULONG_PTR siempre que sea posible.

El puntero PciIoSpaceBase contiene la QVA que se crea en la macro HAL_MAKE_QVA. Esta macro devuelve un valor de 64 bits con los 32 bits principales establecidos en cero para que funcionen las matemáticas. Simplemente podríamos dejar el código para truncar el puntero en un ULONG, pero esta práctica no se recomienda mejorar la capacidad de mantenimiento y la portabilidad del código. Por ejemplo, el contenido de una QVA podría cambiar en el futuro para usar algunos de los bits superiores en este nivel, lo que interrumpirá el código.

Solución

Sea seguro y use ULONG_PTR para todas las matemáticas de dirección y puntero.

HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);

Advertencia C4311 Ejemplo 3

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long'

Código

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);
}

Description

El compilador advierte sobre la dirección de (&) y los operadores de desplazamiento izquierdo (<<) si se aplican a los tipos de puntero. En el código anterior, Qva es un valor PVOID . Es necesario convertirlo en un tipo entero para realizar las matemáticas. Dado que el código debe ser portátil, use ULONG_PTR en lugar de ULONG.

Solución

if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) {
  return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );

Advertencia C4311 Ejemplo 4

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long'

Código

TranslatedAddress->LowPart = (ULONG)HalCreateQva(
*TranslatedAddress, va);

Description

TranslatedAddress es una unión que tiene un aspecto similar al siguiente:

typedef union
   Struct {
      ULONG LowPart;
      LONG Highpart;
   }
   LONGLONG QuadPart;
}

Solución

Saber cuál es el resto del código que puede colocar en Highpart, podemos seleccionar cualquiera de las soluciones que se muestran aquí.

TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );

La macro PtrToUlong trunca el puntero devuelto por HalCreateQva a 32 bits. Sabemos que la QVA devuelta por HalCreateQva tiene los 32 bits superiores establecidos en cero y la siguiente línea de código establece TranslatedAddress-Highpart> en cero.

Con precaución, podríamos usar lo siguiente:

TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);

Esto funciona en este ejemplo: la macro HalCreateQva devuelve 64 bits, con los 32 bits superiores establecidos en cero. Tenga cuidado de no dejar los 32 bits superiores sin definir en un entorno de 32 bits, lo que esta segunda solución puede hacer realmente.

Advertencia C4311 Ejemplo 5

'type cast': truncamiento del puntero de 'void *__ptr64' a 'unsigned long'

Código

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;

Description

WindowRegisters-WindowBase> es un puntero y ahora es de 64 bits. El código indica que cambia a la derecha este valor de 20 bits. El compilador no nos permitirá usar el operador de desplazamiento derecho (>>) en un puntero; por lo tanto, es necesario convertirlo en algún tipo de entero.

Solución

Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));

La conversión a un ULONG_PTR es lo que necesitamos. El siguiente problema es Wbase. Wbase es un ULONG y es de 32 bits. En este caso, sabemos que el puntero de 64 bits WindowRegisters-WindowBase> es válido en los 32 bits inferiores incluso después de cambiarse. Esto hace que el uso de la macro PtrToUlong sea aceptable, ya que truncará el puntero de 64 bits en un ULONG de 32 bits. La conversión PVOID es necesaria porque PtrToUlong espera un argumento de puntero. Al examinar el código del ensamblador resultante, toda esta conversión de código de C se convierte solo en un quad de carga, desplazarse a la derecha y almacenar largo.