一般的なコンパイラ エラー
このセクションでは、既存のコード ベースを移行するときに発生する一般的なコンパイラ エラーについて説明します。 これらの例は、システム レベルの HAL コードから発生しますが、概念はユーザー レベルのコードに直接適用できます。
警告 C4311 例 1
'type cast' : 'void *__ptr64 ' から 'unsigned long' へのポインターの切り捨て
-
コード
-
pPciAddr->u.AsULONG = (ULONG) CIA_PCI_CONFIG_BASE_QVA;
-
Description
-
PtrToUlong は、使用に応じてインライン関数またはマクロです。 ULONG へのポインターを切り捨てます。 32 ビット ポインターは影響を受けませんが、64 ビット ポインターの上半分は切り捨てられます。
CIA_PCI_CONFIG_BASE_QVAは PVOID として宣言されています。 ULONG キャストは 32 ビットの世界で動作しますが、64 ビット世界ではエラーが発生します。 解決策は、pPciAddr-u.AsULONG> が変更で定義されている共用体の定義を変更するコードが多すぎるため、ULONG への 64 ビット ポインターを取得することです。
マクロ PtrToUlong を 使用して 64 ビット PVOID を必要な ULONG に変換することは、CIA_PCI_CONFIG_BASE_QVAの特定の値に関する知識があるためです。 この場合、このポインターは上位 32 ビットのデータを持つことはありません。
-
解決方法
-
pPciAddr->u.AsULONG = PtrToUlong(CIA_PCI_CONFIG_BASE_QVA);
警告 C4311 例 2
'type cast' : 'struct _ERROR_FRAME *__ptr64 ' から 'unsigned long' へのポインターの切り捨て
-
コード
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG)PUncorrectableError );
-
Description
-
問題は、この関数の最後のパラメーターがデータ構造へのポインターであるということです。 PUncorrectableError はポインターであるため、プログラミング モデルでサイズが変更されます。 KeBugCheckEx のプロトタイプは、最後のパラメーターがULONG_PTRになるように変更されました。 その結果、関数ポインターを ULONG_PTRにキャストする必要があります。
PVOID が最後のパラメーターとして使用されなかった理由を尋ねる場合があります。 呼び出しのコンテキストによっては、最後のパラメーターがポインター以外のものか、場合によってはエラー コードである可能性があります。
-
解決方法
-
KeBugCheckEx( DATA_BUS_ERROR,0,0,0,(ULONG_PTR)PUncorrectableError );
警告 C4244 例 1
'=' : 'struct _CONFIGURATION_COMPONENT *__ptr64 ' から 'struct _CONFIGURATION_COMPONENT *' への変換。データが失われる可能性があります
-
コード
-
Component = &CurrentEntry->ComponentEntry;
-
Description
-
関数は、変数 Component をPCONFIGURATION_COMPONENTとして宣言します。 後で、変数は正しく表示される次の代入で使用されます。
Component = &CurrentEntry->ComponentEntry;
ただし、PCONFIGURATION_COMPONENT型は次のように定義されます。
typedef struct __CONFIGURATION_COMPONENT { ... ... } CONFIGURATION_COMPONENT, * POINTER_32 PCONFIGURATION_COMPONENT;
PCONFIGURATION_COMPONENTの型定義では、POINTER_32宣言されているため、32 ビット モデルと 64 ビット モデルの両方で 32 ビット ポインターが提供されます。 この構造の元のデザイナーは、BIOS の 32 ビット コンテキストで使用されることを知り、その使用のために明示的に定義しました。 ポインターは 32 ビットであるため、このコードは 32 ビット Windows で正常に動作します。 64 ビット Windows では、コードが 64 ビット コンテキストにあるため、機能しません。
-
解決方法
-
この問題を回避するには、32 ビット PCONFIGURATION_COMPONENT ではなく CONFIGURATION_COMPONENT * を使用します。 コードの目的を明確に理解することが重要です。 このコードが 32 ビット BIOS またはシステム領域に触れることを意図している場合、この修正は機能しません。
POINTER_32 は Ntdef.h と Winnt.h で定義されています。
#ifdef (__AXP64__) #define POINTER_32 _ptr32 #else #define POINTER_32 #endif
警告 C4242 例 2
'=' : '__int64 ' から 'unsigned long ' への変換。データが失われる可能性があります
-
コード
-
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
-
この警告は、計算で 64 ビット値 (この場合はポインター) を使用し、結果を 32 ビット ULONG に配置しているために生成されます。
-
解決方法
-
次に示すように、計算結果を ULONG にキャストします。
ByteSelect1 = (ULONG)(NvDestPtr - (PUCHAR)HalpCMOSRamBase) & CONFIG_RAM_BYTE_MASK;
結果を型キャストすると、コンパイラは結果について確実であることを知らせます。 つまり、計算を理解し、実際には 32 ビット ULONG に収まることを確認してください。
結果が 32 ビット ULONG に収まらない場合は、結果を保持する変数の基本型を変更します。
警告 C4311 - 例 1
'type cast' : 'void *__ptr64 ' から 'unsigned long ' へのポインターの切り捨て
-
コード
-
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
-
この関数全体はアドレスを整数として扱い、移植可能な方法でこれらの整数を入力する必要があります。 すべてのローカル変数、計算の中間値、および戻り値は移植可能な型である必要があります。
-
解決方法
-
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 は、それ自体が 32 ビット Windows の場合は 32 ビット、64 ビットは 64 ビットのポインターです。 32 ビット Windows の場合は 32 ビット、64 ビットは 64 ビットである符号なし整数 ( ULONG_PTR) を指します。
警告 C4311 - 例 2
'type cast' : 'void *__ptr64 ' から 'unsigned long ' へのポインターの切り捨て
-
コード
-
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
-
すべての QVA (準仮想アドレス) 値は、この段階では実際には 32 ビット値であり、 ULONG に収まりますが、可能であればすべてのアドレスを ULONG_PTR 値として扱う方が一貫性があります。
ポインター PciIoSpaceBase は、マクロ HAL_MAKE_QVAで作成された QVA を保持します。 このマクロは、上位 32 ビットが 0 に設定された 64 ビット値を返し、計算が機能します。 ポインターを ULONG に切り詰めるためにコードを残すだけで済みますが、この方法ではコードの保守性と移植性を強化することはお勧めしません。 たとえば、QVA の内容は将来、このレベルの上位ビットの一部を使用するように変更され、コードが破損する可能性があります。
-
解決方法
-
安全であり、すべてのアドレスとポインターの計算に ULONG_PTR を使用します。
HalpCMOSRamBase = (PVOID)((ULONG_PTR)PciIoSpaceBase + CMOS_ISA_PORT_ADDRESS);
警告 C4311 例 3
'type cast' : 'void *__ptr64 ' から 'unsigned long ' へのポインターの切り捨て
-
コード
-
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
-
コンパイラは、() 演算子と左シフト (&<<) 演算子のアドレスがポインター型に適用されている場合に警告します。 上記のコードでは、Qva は PVOID 値です。 数値演算を実行するには、整数型にキャストする必要があります。 コードは移植可能である必要があるため、ULONG の代わりに ULONG_PTR を使用します。
-
解決方法
-
if ( ((ULONG_PTR) Qva & QVA_SELECTORS) == QVA_ENABLE ) { return( (PVOID)( (ULONG_PTR)Qva << IO_BIT_SHIFT ) );
警告 C4311 例 4
'type cast' : 'void *__ptr64 ' から 'unsigned long ' へのポインターの切り捨て
-
コード
-
TranslatedAddress->LowPart = (ULONG)HalCreateQva( *TranslatedAddress, va);
-
Description
-
TranslatedAddress は、次のような共用体です。
typedef union Struct { ULONG LowPart; LONG Highpart; } LONGLONG QuadPart; }
-
解決方法
-
コードの残りの部分が Highpart に配置される可能性がある内容を把握している場合は、次に示すソリューションのいずれかを選択できます。
TranslatedAddress->LowPart = PtrToUlong(HalCreateQva(*TranslatedAddress,va) );
PtrToUlong マクロは、HalCreateQva によって返されるポインターを 32 ビットに切り捨てます。 HalCreateQva によって返される QVA の上位 32 ビットが 0 に設定され、次のコード行によって TranslatedAddress-Highpart> が 0 に設定されていることがわかります。
注意して、次のものを使用できます。
TranslatedAddress->QuadPart = (LONGLONG)HalCreateQva(*TranslatedAddress,va);
この例では、 HalCreateQva マクロから 64 ビットが返され、上位 32 ビットが 0 に設定されています。 この 2 番目のソリューションが実際に行う可能性がある 32 ビット環境では、上位 32 ビットを未定義のままにしないように注意してください。
警告 C4311 例 5
'type cast' : 'void *__ptr64 ' から 'unsigned long ' へのポインターの切り捨て
-
コード
-
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> はポインターであり、64 ビットになりました。 このコードでは、この値を 20 ビット右シフトすると記述されています。 コンパイラでは、ポインターに対して右シフト (>>) 演算子を使用できません。したがって、何らかの整数にキャストする必要があります。
-
解決方法
-
Wbase.Wbase= PtrToUlong ( (PVOID) ((ULONG_PTR) (WindowRegisters->WindowBase) >> 20));
ULONG_PTRへのキャストは、必要なものにすぎません。 次の問題は Wbase です。 Wbase は ULONG で、32 ビットです。 この場合、64 ビット ポインター WindowRegisters-WindowBase> は、シフトされた後でも下位 32 ビットで有効であることがわかります。 これにより 、PtrToUlong マクロを使用できます。これは、64 ビット ポインターが 32 ビット ULONG に切り捨てられるためです。 PtrToUlong はポインター引数を必要とするため、PVOID キャストが必要です。 結果として得られるアセンブラー コードを見ると、この C コード キャストはすべて単なるロード クワッドになり、右にシフトし、長く格納されます。