2013-02-01 10 views
9

Quando compilo il seguente codice in Delphi XE2 per la piattaforma di destinazione a 64 bit di Windows ...Perché ottengo "L'espressione costante viola i subrange bound" per le costanti HKEY_ in Delphi XE2 a 64 bit?

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; 

... ricevo avvertimenti per ciascuno dei HKEY_-Costanti: "espressione costante W1012 viola subrange limiti"

ho controllato le dichiarazioni in Winapi.Windows (con Ctrl + Pulsante sinistro sugli identificatori):

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

Questi guardare bene a me. Perché il compilatore pensa ancora che ci sia un problema?

+0

Suoni plausibili, quindi la soluzione sarebbe quella di utilizzare se le dichiarazioni invece? – dummzeuch

+4

Estratto da doc ['# Case_Statements'] (http://docwiki.embarcadero.com/RADStudio/XE3/en/Declarations_and_Statements#Case_Statements):" .. dove selectorExpression è qualsiasi espressione di un tipo ordinale inferiore a 32 bit (stringa tipi e ordinali maggiori di 32 bit non sono validi). " –

+1

@LURD Non prenderò la documentazione XE3 per accurate, quando si tratta di 64 bit (e anche di CrossPlatform). È deprecato per i nuovi obiettivi e non è stato aggiornato (hai ancora riferimenti "Linux" e descrizioni specifiche per Win32 - vedi [ad esempio questa pagina] (http://docwiki.embarcadero.com/RADStudio/XE3/en/ Program_Control)). Ma in questo caso, sembra una vera e propria limitazione - anche se non è obbligatoria, dal punto di vista asm generato, dato che a 64 bit, puoi usare i registri x64 sul backend per controllare il 'caso'. Quindi suppongo che il frontend del compilatore non sia stato aggiornato per il contesto a 64 bit. –

risposta

8

Sulla compilatore 64 bit del valore effettivo di HKEY_CLASSES_ROOT è:

FFFFFFFF80000000 

Questo perché il cast Integer fa 80000000 in un numero negativo. E poi la conversione in unsigned porta a FFFFFFFF80000000. Si noti che questo valore è corretto. La dichiarazione nel file di Windows intestazione è:

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

e quando si include il file di intestazione e ispezionare il valore di HKEY_CLASSES_ROOT in un programma C++, è esattamente lo stesso valore per la dichiarazione Delphi.

E poi possiamo risolvere il puzzle dalla documentazione Delphi cui si afferma che le selectors in a case statement can only be:

ogni espressione di un tipo ordinale inferiori a 32 bit

non hai scelta, ma per sostituire la tua istruzione case con una dichiarazione if.

+0

Mi dispiace, ma * avete la scelta * di usare 'caso', a causa dei possibili valori limitati delle costanti di' HKEY_ * '. Vedi la mia risposta e i commenti sopra. –

+0

Se si vuole far finta che gli HKEY abbiano una larghezza di 32 bit e corrano il rischio di falsi positivi con chiavi non predefinite, allora è ciò che dice Arnaud. Ma questo è un modo terribile di codificare. Affidandosi ai dettagli di implementazione e troncando i valori a 64 bit a 32 bit. Sono inorridito al solo pensiero. –

1

HKEY=UINT_PTR è un numero intero a 64 bit senza segno nel tuo caso e la dichiarazione case ... of sembra non gestirla.

Il front-end del compilatore XE2/XE3 presuppone ancora che sia destinato a una piattaforma a 32 bit, anche se non vi è alcun motivo tecnico per il back-end del compilatore che non sia in grado di gestire istruzioni caso a 64 bit (con il classico modello di generazione codice sub register,constant; jz @... asm).

Si può provare a typecast tutto per 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 
... 

o semplicemente ignorare le upmost 32 bit del valore _HKey (questo è lo stesso):

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

Essa funzionerà come previsto sotto Windows: a causa del numero limitato di costanti HKEY_*, penso che si possa semplicemente ignorare il massimo 32 bit del valore _HKey e quindi utilizzare il passegginoDichiarazione. E funzionerà ovviamente sia per Win32 che per Win64.

Ho il sospetto che anche ... and $f sia sufficiente - vedi tutte le costanti HKEY_*.

Ultima (e certamente la soluzione migliore) è quella di utilizzare il buon vecchio nidificate if... else if... dichiarazioni:

function HKeyToString(_HKey: HKey): string; 
begin 
    if_HKey=HKEY_CLASSES_ROOT then 
    result := 'HKEY_CLASSES_ROOT' else // do not translate 
    if_HKey=HKEY_CURRENT_USER then 
    result := 'HKEY_CURRENT_USER' else // do not translate 
.... 

Credo che l'ultimo è preferito, e non più lento, con le CPU condotte moderni.

+0

Il valore di 'HKEY_CLASSES_ROOT32' è' 0000000080000000' e questo è sbagliato. Deve essere 'FFFFFFFF80000000'. –

+0

@DavidHeffernan Ovviamente, poiché il parametro '_HKey' è stato ridefinito come' numero intero 'nella funzione' HKeyToString (_HKey: intero): stringa; ', se corrisponderà al valore' HKEY_CLASSES_ROOT32', ignorando semplicemente il DWord superiore del valore originale 'HKey'. Funzionerà come previsto in Windows: a causa del numero limitato di costanti 'HKEY_ *', penso che puoi semplicemente ignorare i 32 bit più alti del valore '_HKey', e quindi usare il caso 'buggy' _HKey di ...' dichiarazione. –

+0

È come ignorare i primi 32 bit di un puntatore. Attendi fino a quando RegOpenKeyEx ti offre un HKEY con bit alti impostati. –