2013-02-01 3 views
9

は、私がターゲットプラットフォーム64ビットWindows用のDelphi XE2に次のコードをコンパイルすると... Delphi XE2 64bitのHKEY_-constantsの "Constant expression violation subrange bounds"が表示されるのはなぜですか?

function HKeyToString(_HKey: HKey): string; 
begin 
    case _HKey of 
    HKEY_CLASSES_ROOT: result := 'HKEY_CLASSES_ROOT'; // do not translate 
    HKEY_CURRENT_USER: result := 'HKEY_CURRENT_USER'; // do not translate 
    HKEY_LOCAL_MACHINE: result := 'HKEY_LOCAL_MACHINE'; // do not translate 
    HKEY_USERS: result := 'HKEY_USERS'; // do not translate 
    HKEY_PERFORMANCE_DATA: result := 'HKEY_PERFORMANCE_DATA'; // do not translate 
    HKEY_CURRENT_CONFIG: result := 'HKEY_CURRENT_CONFIG'; // do not translate 
    HKEY_DYN_DATA: result := 'HKEY_DYN_DATA'; // do not translate 
    else 
    Result := Format(_('unknown Registry Root Key %x'), [_HKey]); 
    end; 
end; 

...私はHKEY_-定数のそれぞれに対して警告を得る: 「W1012定数式は、サブレンジに違反します境界」

私は(識別子にはCtrl + Leftclickで)Winapi.Windowsで宣言をチェックする:

type 
    HKEY = type UINT_PTR; 
{...} 
const 
    HKEY_CLASSES_ROOT  = HKEY(Integer($80000000)); 

これらは私には罰金に見えます。なぜコンパイラはまだ問題があると思いますか?

+0

サウンドはそう考えられます。だから、解決策は代わりにif文を使うことでしょうか? – dummzeuch

+4

doc ['#Case_Statements'](http://docwiki.embarcadero.com/RADStudio/XE3/en/Declarations_and_Statements#Case_Statements)からの抽出:" ..ここで、selectorExpressionは32ビットより小さい序数型の式です(string 32ビットより大きい型と序数は無効です)。 " –

+1

@LURD 64ビット(さらにはCrossPlatform)を扱う場合、XE3のドキュメントを正確には取り上げません。新しいターゲットではあまり使用されず、リフレッシュされていません(LinuxのリファレンスとWin32固有の記述があります - このページの例を参照)(http://docwiki.embarcadero.com/RADStudio/XE3/en/ Program_Control))。しかし、この場合、実際の制限のように聞こえます。たとえ必須ではないとしても、生成されたasmの観点からは、64ビットでバックエンドのx64レジスタを使用して 'case'をチェックできます。だから、コンパイラのフロントエンドは64ビットのコンテキストのために更新されていないと思う。 –

答えて

8

Integerへのキャストが負の数に 80000000を作るためだ
FFFFFFFF80000000 

。そして、符号なしに変換するとFFFFFFFF80000000になります。この値は正しいことに注意してください。窓のヘッダー・ファイル内の宣言は次のとおりです。

#define HKEY_CLASSES_ROOT ((HKEY) (ULONG_PTR)((LONG)0x80000000)) 

、あなたはヘッダファイルをインクルードし、C++プログラムでHKEY_CLASSES_ROOTの値を検査するとき、それは、Delphiの宣言とまったく同じ値です。

そして、我々はselectors in a case statement can only beと述べているDelphiのドキュメントからパズルを解くことができます。

32ビット

よりも小さい順序型の任意の式あなたが交換するしかありませんあなたのcaseステートメントはifステートメントです。

+0

申し訳ありませんが、 'HKEY_ * '定数の値が限られているため、' case'を使用する選択肢*があります。私の答えと上記のコメントを参照してください。 –

+0

あなたは、HKEYが32ビット幅であることをふりかえり、あらかじめ定義されていないキーで偽陽性のリスクを冒したければ、Arnaudの言葉をあなたに伝えてください。しかしそれはコード化するためのひどい方法です。実装の詳細に頼って、64ビット値を32ビットに切り詰める。私はそれについて考えてみるとぞっとする。 –

1

HKEY=UINT_PTRは、あなたのケースでは符号なし64ビット整数であり、case ... ofステートメントはそれを処理しないようです。

XE2/XE3コンパイラフロントエンドは、コンパイラのバックエンドが64ビットのcase文を処理できないという技術的な理由がない場合でも、32ビットプラットフォームをターゲットとしています(従来のsub register,constant; jz @... asmコード生成パターン)。

あなたはintegerにすべてを型キャストしようとすることができます:

const 
    HKEY_CLASSES_ROOT32 = Integer($80000000); 

... 

function HKeyToString(_HKey: integer): string; 
begin 
    case _HKey of 
    HKEY_CLASSES_ROOT32: result := 'HKEY_CLASSES_ROOT'; // do not translate 
... 

またはちょうど_HKey値の最上32ビット(これは同じである)を無視:期待通りに動作します

function HKeyToString(_HKey: HKey): string; 
begin 
    case _HKey and $ffffffff of 
    HKEY_CLASSES_ROOT and $ffffffff: result := 'HKEY_CLASSES_ROOT'; // do not translate 
... 

をWindowsの場合:HKEY_*定数の数が限られているため、_HKeyの最上位32ビットを無視できるので、バグcase .. of...ステートメント。もちろん、Win32とWin64の両方で動作します。

私も... and $fは十分でしょう疑う - すべてHKEY_*定数を参照してください。

最終(と確かに最善の解決策は)古き良きネストされたif... else if...ステートメントを使用することです:

​​

私は、最後の一つは、現代のパイプラインのCPUを搭載した、遅く好ましく、されていないと思います。 HKEY_CLASSES_ROOTの実際の値である64ビットコンパイラで

+0

'HKEY_CLASSES_ROOT32'の値が' 0000000080000000'であり、間違っています。 'FFFFFFFF80000000'でなければなりません。 –

+0

@DavidHeffernanもちろん、 'HKEY_CLASSES_ROOT32'値と一致する場合、' _HKey'パラメータは 'function HKeyToString(_HKey:integer):string;'の 'integer'として再定義されているので、元の 'HKey'値です。 Windowsでは期待通りに動作します: 'HKEY_ *'定数の数が限られているため、 '_HKey'値の最上位32ビットを無視するだけで、バグ' case _HKey of ... 'を使うことができます。ステートメント。 –

+0

これは、ポインタの上位32ビットを無視するようなものです。 RegOpenKeyExが高いビットが設定されたHKEYを返すまで待ち​​ます。 –