Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Det här avsnittet illustrerar de typiska kompilatorfel som uppstår när du migrerar en befintlig kodbas. De här exemplen kommer från HAL-kod på systemnivå, även om begreppen är direkt tillämpliga på kod på användarnivå.
Varning C4311 Exempel 1
"type cast" : pekarens trunkering från "void *__ptr64" till "unsigned long
-
Code
-
pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA; -
beskrivning
-
PtrToUlong är en infogad funktion eller makro, beroende på din användning. Den trunkerar en pekare till en ULONG-. Även om 32-bitars pekare inte påverkas trunkeras den övre halvan av en 64-bitars pekare.
CIA_PCI_CONFIG_BASE_QVA deklareras som en PVOID-. Den ULONG- cast fungerar i 32-bitarsvärlden, men resulterar i ett fel i 64-bitarsvärlden. Lösningen är att hämta en 64-bitars pekare till en ULONG-eftersom det definieras för mycket kod för att ändra definitionen av unionen som pPciAddr–>u.AsULONG.
Att använda makrot PtrToUlong för att konvertera 64-bitars PVOID- till den nödvändiga ULONG- tillåts eftersom vi har kunskap om det specifika värdet för CIA_PCI_CONFIG_BASE_QVA. I det här fallet kommer den här pekaren aldrig att ha data i de övre 32 bitarna.
-
lösning
-
pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);
Varning C4311 Exempel 2
"type cast" : pekare trunkering från "struct _ERROR_FRAME *__ptr64 " till "unsigned long
-
Code
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError ); -
beskrivning
-
Problemet är att den sista parametern för den här funktionen är en pekare till en datastruktur. Eftersom PUncorrectableError är en pekare ändrar den storlek med programmeringsmodellen. Prototypen för KeBugCheckEx har ändrats så att den sista parametern är en ULONG_PTR. Därför är det nödvändigt att omvandla funktionspekaren till en ULONG_PTR.
Du kan fråga dig varför PVOID- inte användes som den sista parametern. Beroende på anropets kontext kan den sista parametern vara något annat än en pekare eller kanske en felkod.
-
lösning
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );
Varning C4244 Exempel 1
=: konvertering från "struct _CONFIGURATION_COMPONENT *__ptr64 " till "struct _CONFIGURATION_COMPONENT *", eventuell dataförlust
-
Code
-
Component = &CurrentEntry->ComponentEntry; -
beskrivning
-
Funktionen deklarerar variabelkomponenten som en PCONFIGURATION_COMPONENT. Senare används variabeln i följande tilldelning som ser korrekt ut:
Component = &CurrentEntry->ComponentEntry;Typen PCONFIGURATION_COMPONENT definieras dock som:
typedef struct __CONFIGURATION_COMPONENT { ... ... } CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;Typdefinitionen för PCONFIGURATION_COMPONENT innehåller en 32-bitars pekare i både 32-bitars- och 64-bitarsmodeller eftersom den deklareras POINTER_32. Den ursprungliga designern av den här strukturen visste att den skulle användas i en 32-bitars kontext i BIOS och definierade den uttryckligen för den användningen. Den här koden fungerar bra i 32-bitars Windows eftersom pekarna råkar vara 32-bitars. I 64-bitars Windows fungerar det inte eftersom koden finns i 64-bitarskontext.
-
lösning
-
Du kan undvika det här problemet genom att använda CONFIGURATION_COMPONENT * i stället för 32-bitars PCONFIGURATION_COMPONENT . Det är viktigt att tydligt förstå syftet med koden. Om den här koden är avsedd att röra 32-bitars BIOS eller systemutrymme fungerar inte den här korrigeringen.
POINTER_32 definieras i Ntdef.h och Winnt.h.
#ifdef (__AXP64__) #define POINTER_32 _ptr32 #else #define POINTER_32 #endif
Varning C4242 Exempel 2
=: konvertering från "__int64" till "osignerad lång", eventuell dataförlust
-
Code
-
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; -
beskrivning
-
Den här varningen genereras eftersom beräkningen använder 64-bitarsvärden, i det här fallet pekare och placerar resultatet i en 32-bitars ULONG-.
-
lösning
-
Skriv cast resultatet av beräkningen till en ULONG- som visas här:
ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;Genom att skriva resultatet kan kompilatorn veta att du är säker på resultatet. Med detta sagt, se till att du förstår beräkningen och verkligen är säker på att det kommer att passa i en 32-bitars ULONG.
Om resultatet kanske inte får plats i en 32-bitars ULONG-ändrar du bastypen för variabeln som ska innehålla resultatet.
Varning C4311 – Exempel 1
"type cast" : pekarens trunkering från "void *__ptr64 " till "unsigned long"
-
Code
-
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; } -
beskrivning
-
Hela den här funktionen hanterar adresser som heltal, vilket kräver att du skriver dessa heltal på ett bärbart sätt. Alla lokala variabler, mellanliggande värden i beräkningar och returvärden ska vara portabla typer.
-
lösning
-
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 är en pekare som i sig är 32 bitar för 32-bitars Windows och 64 bitar för 64-bitars Windows. Den pekar på ett osignerat heltal, ULONG_PTR, som är 32 bitar för 32-bitars Windows och 64 bitar för 64-bitars Windows.
Varning C4311 – Exempel 2
"type cast" : pekarens trunkering från "void *__ptr64 " till "unsigned long"
-
Code
-
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); -
beskrivning
-
Även om alla QVA-värden (kvasi virtuell adress) verkligen är 32-bitarsvärden i det här skedet och får plats i en ULONG-är det mer konsekvent att behandla alla adresser som ULONG_PTR värden när det är möjligt.
Pekaren PciIoSpaceBase innehåller den QVA som skapas i makrot HAL_MAKE_QVA. Det här makrot returnerar ett 64-bitarsvärde med de översta 32 bitarna inställda på noll så att matematiken fungerar. Vi skulle helt enkelt kunna låta koden trunkera pekaren till en ULONG-, men den här metoden rekommenderas inte för att förbättra kodunderhållbarheten och portabiliteten. Till exempel kan innehållet i en QVA ändras i framtiden för att använda några av de övre bitarna på den här nivån, vilket bryter koden.
-
lösning
-
Var säker och använd ULONG_PTR för all adress- och pekarmatematik.
HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
Varning C4311 Exempel 3
"type cast" : pekarens trunkering från "void *__ptr64 " till "unsigned long"
-
Code
-
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); } -
beskrivning
-
Kompilatorn varnar om adressen för operatorerna (&) och vänster skift (<<) om de tillämpas på pekartyper. I koden ovan är Qva ett PVOID- värde. Vi måste omvandla det till en heltalstyp för att utföra matematiken. Eftersom koden måste vara portabel använder du ULONG_PTR i stället för ULONG-.
-
lösning
-
if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );
Varning C4311 Exempel 4
"type cast" : pekarens trunkering från "void *__ptr64 " till "unsigned long"
-
Code
-
TranslatedAddress->LowPart = (ULONG)HalCreateQva( *TranslatedAddress, va); -
beskrivning
-
TranslatedAddress är en union som ser ut ungefär så här:
typedef union Struct { ULONG LowPart; LONG Highpart; } LONGLONG QuadPart; } -
lösning
-
Med vetskapen om vad resten av koden kan placera i Highpart kan vi välja någon av de lösningar som visas här.
TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );PtrToUlong makrot trunkerar pekaren som returneras av HalCreateQva till 32 bitar. Vi vet att QVA som returneras av HalCreateQva har de övre 32 bitarna inställda på noll och nästa rad med koduppsättningar TranslatedAddress->Highpart till noll.
Med försiktighet kan vi använda följande:
TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);Detta fungerar i det här exemplet: HalCreateQva makro returnerar 64 bitar, med de övre 32 bitarna inställda på noll. Var bara noga med att inte lämna de övre 32 bitarna odefinierade i en 32-bitars miljö, vilket den andra lösningen faktiskt kan göra.
Varning C4311 Exempel 5
"type cast" : pekarens trunkering från "void *__ptr64 " till "unsigned long"
-
Code
-
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; -
beskrivning
-
WindowRegisters –>WindowBase är en pekare och är nu 64 bitar. Koden säger att högerförskjuta det här värdet 20 bitar. Kompilatorn låter oss inte använda operatorn right-shift (>>) på en pekare. Därför måste vi kasta den till något slags heltal.
-
lösning
-
Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));Att kasta till en ULONG_PTR är precis vad vi behöver. Nästa problem är Wbase. Wbase är en ULONG- och är 32 bitar. I det här fallet vet vi att 64-bitarspekaren WindowRegisters–>WindowBase är giltig i de lägre 32 bitarna även efter att ha flyttats. Detta använder PtrToUlong- makrot acceptabelt, eftersom det trunkerar 64-bitarspekaren till en 32-bitars ULONG-. Det PVOID cast är nödvändigt eftersom PtrToUlong förväntar sig ett pekarargument. När du tittar på den resulterande monteringskoden blir all denna C-kodgjutning bara en belastnings quad, skift höger och lagra länge.