2009-07-21 14 views
9

Ho una piccola domanda sulle strutture con il set di attributi LayoutKind.Explicit. Ho dichiarato il struct come si può vedere, con un fieldTotal a 64 bit, che è fieldFirst i primi 32 byte e fieldSecond gli ultimi 32 byte. Dopo aver impostato sia fieldfirst e fieldSecond a Int32.MaxValue, mi aspetto che lo fieldTotal sia Int64.MaxValue, che in realtà non accade. Perchè è questo? So che C# non supporta veramente i sindacati C++, forse leggerà bene i valori solo quando interope- rano, ma quando proviamo a impostare noi stessi i valori, semplicemente non lo gestiremo molto bene?Come posso simulare un unione C++ in C#?

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT { 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(32)] 
    public Int32 fieldSecond; 
} 

     STRUCT str = new STRUCT(); 
     str.fieldFirst = Int32.MaxValue; 
     str.fieldSecond = Int32.MaxValue; 
     Console.WriteLine(str.fieldTotal); // <----- I'd expect both these values 
     Console.WriteLine(Int64.MaxValue); // <----- to be the same. 
     Console.ReadKey(); 

risposta

10

Il motivo è che FieldOffsetAttribute accetta un numero di byte come parametro, non il numero di bit. Questo funziona come previsto:

[StructLayout(LayoutKind.Explicit)] 
struct STRUCT 
{ 
    [FieldOffset(0)] 
    public Int64 fieldTotal; 

    [FieldOffset(0)] 
    public Int32 fieldFirst; 

    [FieldOffset(4)] 
    public Int32 fieldSecond; 
} 
+0

Inoltre, ciò che Reed e Jared dicono di firmati e non firmati. –

6

Guardando i valori esadecimali se Int32.MaxValue e Int64.MaxValue dovrebbero fornire la risposta.

La chiave è il bit più significativo. Per un numero intero positivo, il bit più significativo è impostato solo per un numero negativo. Quindi il valore massimo di Int32 è uno 0 seguito da un'intera serie di 1s. L'ordine non è importante, solo che ci sarà almeno un singolo 0 bit. Lo stesso vale per Int64.MaxValue.

Considerate ora come dovrebbe funzionare un sindacato. Disporterà essenzialmente i bit dei valori l'uno accanto all'altro. Quindi ora hai un set di bit 64 di lunghezza che contiene due valori a 0 bit. Uno per ciascuna delle istanze Int32.MaxValue. Questo non può mai essere uguale a Int64.MaxValue poiché può contenere solo un singolo 0 bit.

Stranamente, probabilmente si otterrà il comportamento che si sta cercando se si imposta fieldSecond su Int32.MinValue.

EDIT Manca che è necessario renderlo FieldOffset (4) pure.

4

Ben M fornito uno degli elementi più importanti - la vostra definizione non è configurato correttamente.

Detto questo, questo non funzionerà - anche in C++ con un sindacato. I valori che hai specificato non saranno (e non dovrebbero essere) gli stessi valori, dal momento che stai usando inti firmati (non firmati). Con un int firmato (Int32), avrai un bit 0 seguito da 1 bit. Quando fai il sindacato, finirai con un 0 bit, seguito da un gruppo di 1 bit, poi un altro 0 bit, quindi un gruppo di 1 bit ... Il secondo 0 bit è ciò che ti incasina.

Se si utilizza UInt32/UInt64, questa operazione funzionerà, poiché il bit di segno aggiuntivo non esiste.

+0

Sì, hai ragione. Con quello che hai detto e Ben ha detto, funziona come previsto. Grazie! –