一般的なコンパイラ エラー

このセクションでは、既存のコード ベースを移行するときに発生する一般的なコンパイラ エラーについて説明します。 これらの例は、システム レベルの 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 コード キャストはすべて単なるロード クワッドになり、右にシフトし、長く格納されます。