Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
Esta seção ilustra os erros típicos do compilador que ocorrem ao migrar uma base de código existente. Esses exemplos são do código HAL no nível do sistema, embora os conceitos sejam diretamente aplicáveis ao código no nível do usuário.
Aviso C4311 Exemplo 1
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para 'unsigned long
-
Código
-
pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA; -
Descrição
-
PtrToUlong é uma função em linha ou macro, dependendo do seu uso. Ele trunca um ponteiro para um ULONG. Embora os ponteiros de 32 bits não sejam afetados, a metade superior de um ponteiro de 64 bits é truncada.
CIA_PCI_CONFIG_BASE_QVA é declarado como um PVOID. O ULONG cast funciona no mundo de 32 bits, mas resulta em um erro no mundo de 64 bits. A solução é obter um ponteiro de 64 bits para um ULONG, porque alterar a definição da união que pPciAddr->u.AsULONG é definido em altera muito código.
Usando o de macro PtrToUlong para converter o PVOID de 64 bits para o ULONG necessário é permitido porque temos conhecimento sobre o valor específico de CIA_PCI_CONFIG_BASE_QVA. Neste caso, este ponteiro nunca terá dados nos 32 bits superiores.
-
Solução
-
pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);
Aviso C4311 Exemplo 2
'Type Cast' : truncamento de ponteiro de 'struct _ERROR_FRAME *__ptr64 ' para 'long não assinado
-
Código
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError ); -
Descrição
-
O problema é que o último parâmetro para esta função é um ponteiro para uma estrutura de dados. Como PUncorrectableError é um ponteiro, ele muda de tamanho com o modelo de programação. O protótipo para KeBugCheckEx foi alterado para que o último parâmetro seja um ULONG_PTR. Como resultado, é necessário lançar o ponteiro da função para um ULONG_PTR.
Você pode perguntar por que PVOID não foi usado como o último parâmetro. Dependendo do contexto da chamada, o último parâmetro pode ser algo diferente de um ponteiro ou talvez um código de erro.
-
Solução
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );
Aviso C4244 Exemplo 1
'=' : conversão de 'struct _CONFIGURATION_COMPONENT *__ptr64 ' para 'struct _CONFIGURATION_COMPONENT *', possível perda de dados
-
Código
-
Component = &CurrentEntry->ComponentEntry; -
Descrição
-
A função declara a variável Component como um PCONFIGURATION_COMPONENT. Mais tarde, a variável é usada na seguinte atribuição que parece correta:
Component = &CurrentEntry->ComponentEntry;No entanto, o tipo PCONFIGURATION_COMPONENT é definido como:
typedef struct __CONFIGURATION_COMPONENT { ... ... } CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;A definição de tipo para PCONFIGURATION_COMPONENT fornece um ponteiro de 32 bits em modelos de 32 bits e 64 bits porque é declarada POINTER_32. O designer original desta estrutura sabia que ela seria usada em um contexto de 32 bits no BIOS e a definiu expressamente para esse uso. Este código funciona bem no Windows de 32 bits porque os ponteiros são de 32 bits. No Windows de 64 bits, ele não funciona porque o código está no contexto de 64 bits.
-
Solução
-
Para contornar esse problema, use CONFIGURATION_COMPONENT * em vez do PCONFIGURATION_COMPONENT de 32 bits. É importante compreender claramente a finalidade do código. Se esse código se destinar a tocar no BIOS de 32 bits ou no espaço do sistema, essa correção não funcionará.
POINTER_32 é definido em Ntdef.h e Winnt.h.
#ifdef (__AXP64__) #define POINTER_32 _ptr32 #else #define POINTER_32 #endif
Aviso C4242 Exemplo 2
'=' : conversão de '__int64 ' para 'long não assinado', possível perda de dados
-
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; -
Descrição
-
Esse aviso é gerado porque o cálculo está usando valores de 64 bits, neste caso ponteiros, e colocando o resultado em um ULONG de 32 bits.
-
Solução
-
Digite cast o resultado do cálculo para um ULONG como mostrado aqui:
ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;Typecasting o resultado permite que o compilador saiba que você tem certeza sobre o resultado. Dito isso, certifique-se de entender o cálculo e realmente tenha certeza de que ele se encaixará em um de 32 bitsULONG.
Se o resultado pode não caber em um ULONG de 32 bits, altere o tipo de base da variável que manterá o resultado.
Aviso C4311 - Exemplo 1
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para '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; } -
Descrição
-
Toda esta função lida com endereços como inteiros, necessitando da necessidade de digitar esses inteiros de forma portátil. Todas as variáveis locais, valores intermediários nos cálculos e valores de retorno devem ser tipos portáteis.
-
Solução
-
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 é um ponteiro que é em si 32 bits para o Windows de 32 bits e 64 bits para o Windows de 64 bits. Ele aponta para um inteiro não assinado, ULONG_PTR, ou seja, 32 bits para Windows de 32 bits e 64 bits para Windows de 64 bits.
Aviso C4311 - Exemplo 2
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para '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); -
Descrição
-
Mesmo que todos os valores QVA (Quasi Virtual Address) sejam realmente valores de 32 bits neste estágio e se encaixem em um ULONG, é mais consistente tratar todos os endereços como valores ULONG_PTR quando possível.
O ponteiro PciIoSpaceBase contém o QVA que é criado na macro HAL_MAKE_QVA. Essa macro retorna um valor de 64 bits com os 32 bits principais definidos como zero para que a matemática funcione. Poderíamos simplesmente deixar o código para truncar o ponteiro em um ULONG, mas essa prática é desencorajada para melhorar a manutenção e a portabilidade do código. Por exemplo, o conteúdo de um QVA pode mudar no futuro para usar alguns dos bits superiores neste nível, quebrando o código.
-
Solução
-
Seja seguro e use ULONG_PTR para todas as matemáticas de endereço e ponteiro.
HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
Aviso C4311 Exemplo 3
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para '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); } -
Descrição
-
O compilador avisa sobre o endereço dos operadores (&) e deslocamento para a esquerda (<<) se eles forem aplicados a tipos de ponteiro. No código acima, Qva é um valor de PVOID. Precisamos converter isso para um tipo inteiro para realizar a matemática. Como o código deve ser portátil, use ULONG_PTR em vez de ULONG.
-
Solução
-
if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );
Aviso C4311 Exemplo 4
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para 'unsigned long '
-
Código
-
TranslatedAddress->LowPart = (ULONG)HalCreateQva( *TranslatedAddress, va); -
Descrição
-
TranslatedAddress é uma união que se parece com o seguinte:
typedef union Struct { ULONG LowPart; LONG Highpart; } LONGLONG QuadPart; } -
Solução
-
Sabendo o que o resto do código pode colocar em Highpart, podemos selecionar qualquer uma das soluções mostradas aqui.
TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );A macro PtrToUlong trunca o ponteiro retornado pelo HalCreateQva para 32 bits. Sabemos que o QVA retornado pelo HalCreateQva tem os 32 bits superiores definidos como zero e a próxima linha de código define TranslatedAddress->Highpart como zero.
Com cautela, podemos usar o seguinte:
TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);Isso funciona neste exemplo: a macro HalCreateQva está retornando 64 bits, com os 32 bits superiores definidos como zero. Apenas tenha cuidado para não deixar os 32 bits superiores indefinidos em um ambiente de 32 bits, o que esta segunda solução pode realmente fazer.
Aviso C4311 Exemplo 5
'Type Cast' : truncamento do ponteiro de 'void *__ptr64 ' para '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; -
Descrição
-
WindowRegisters->WindowBase é um ponteiro e agora é de 64 bits. O código diz para deslocar à direita este valor de 20 bits. O compilador não nos permitirá usar o operador right-shift (>>) em um ponteiro; portanto, precisamos lançá-lo para algum tipo de inteiro.
-
Solução
-
Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));Lançar para um ULONG_PTR é exatamente o que precisamos. O próximo problema é o Wbase. Wbase é um ULONG e é de 32 bits. Neste caso, sabemos que o ponteiro de 64 bits WindowRegisters->WindowBase é válido nos 32 bits inferiores mesmo depois de ser deslocado. Isso torna o uso do PtrToUlong macro aceitável, porque ele truncará o ponteiro de 64 bits em um ULONG de 32 bits. O PVOID cast é necessário porque PtrToUlong espera um argumento de ponteiro. Quando você olha para o código assembler resultante, toda essa transmissão de código C se torna apenas um quad de carga, deslocamento para a direita e armazenamento longo.