2012-06-01 12 views
5

Ho una struttura con campi di bit (totalmente a 32 bit di larghezza) e ho una variabile a 32 bit. Quando provo ad assegnare il valore della variabile al mio struct, ho ottenuto un errore:Come assegnare un valore a una struttura con campi bit?

error: conversion from ‘uint32_t {aka unsigned int}’ to non-scalar type ‘main()::CPUID’ requested.

struct CPUIDregs 
    { 
     uint32_t EAXBuf; 
    }; 
CPUIDregs CPUIDregsoutput; 


int main() { 

struct CPUID   
    { 
      uint32_t Stepping   : 4;   
      uint32_t Model   : 4;   
      uint32_t FamilyID   : 4;   
      uint32_t Type    : 2;   
      uint32_t Reserved1  : 2;   
      uint32_t ExtendedModel : 4;   
      uint32_t ExtendedFamilyID : 8;   
      uint32_t Reserved2  : 4;   
    }; 

    CPUID CPUIDoutput = CPUIDregsoutput.EAXBuf; 

Avete qualche idea di come farlo nella via più breve? Grazie

P.S. Ovviamente ho un valore più appropriato di EAX nel codice reale, ma suppongo che non influenzi qui.

+3

Si potrebbe desiderare un 'unione' piuttosto che una 'struct' qui. Altrimenti puoi impostare separatamente ciascuna variabile nella struct. non si può fare 'CPUID CPUIDoutput = EAX;' si dovrà fare 'CPUIDoutput.stepping = EAX;' – andre

risposta

7

Non dovresti mai fare affidamento su come il compilatore espone la tua struttura in memoria. Ci sono modi per fare ciò che vuoi con un singolo incarico, ma non lo consiglierò né dirò.

Il modo migliore per fare l'assegnazione sarebbe il seguente:

static inline void to_id(struct CPUid *id, uint32_t value) 
{ 
    id->Stepping   = value & 0xf; 
    id->Model   = (value & (0xf << 4)) >> 4; 
    id->FamilyID   = (value & (0xf << 8)) >> 8; 
    id->Type    = (value & (0x3 << 12)) >> 12; 
    id->Reserved1  = (value & (0x3 << 14)) >> 14; 
    id->ExtendedModel = (value & (0xf << 16)) >> 16; 
    id->ExtendedFamilyID = (value & (0xff << 20)) >> 20; 
    id->Reserved2  = (value & (0xf << 28)) >> 28; 
} 

E l'opposto

static inline uint32_t from_id(struct CPUid *id) 
{ 
    return id->Stepping 
     + ((uint32_t)id->Model << 4) 
     + ((uint32_t)id->FamilyID << 8) 
     + ((uint32_t)id->Type << 12) 
     + ((uint32_t)id->Reserved1 << 14) 
     + ((uint32_t)id->ExtendedModel << 16) 
     + ((uint32_t)id->ExtendedFamilyID << 20) 
     + ((uint32_t)id->Reserved2 << 28); 
} 
+0

Ora, vedo solo questo modo di assegnazione per me. – Irina

+0

@ user1430759. Questo è l'unico modo sicuro/portatile per farlo. Non preoccuparti delle prestazioni poiché questo verrà ottimizzato dal compilatore. Inoltre, prova a ricontrollare i numeri prima di copiare il codice. – Shahbaz

+0

E non esitare a votare e accettare se ti è piaciuta la risposta;) – Shahbaz

1

Questi sono membri struct, quindi è necessario assegnarli direttamente o assicurarsi che l'RHS del proprio incarico sia un valore di tipo CPUID. Non sono sicuro del motivo per cui ti aspetti di poter assegnare alla struct da un numero intero.

Il fatto che la struttura contenga bitfield e che la somma dei bit sia uguale al numero di bit nel numero intero che si sta tentando di assegnare, non significa nulla. Non sono ancora tipi compatibili, a scopo di assegnazione.

Se questo fosse troppo vago, prendere in considerazione la visualizzazione di codice migliore/migliore.

+0

Immagino che nella versione modificata del codice sia più ovvio perché sto cercando di assegnare EAX all'intera struttura in una sola volta. Quindi, comunque, se ti ho capito bene, non è possibile che io lo faccia? Posso solo assegnare ciascun campo separatamente? – Irina

2

Proprio se somebody's interessati, Ive ha ottenuto una soluzione migliore per il mio domanda:

*(reinterpret_cast<uint32_t *> (&CPUIDoutput)) = CPUIDregsoutput.EAXBuf; 
+1

Questo è ancora peggio del mio suggerimento sindacale. –

+1

@Anna, spero che non lo stiate usando in codice reale che verrebbe utilizzato in situazioni reali. Il problema è che il compilatore è libero di aggiungere padding tra i membri della tua struct per scopi di ottimizzazione. Quindi, non puoi fare affidamento sulla tua struttura e sul tuo numero per avere lo stesso layout. Anche senza padding, la tua affermazione sarà assolutamente sbagliata in una macchina big-endian. – Shahbaz

3

Utilizzare un sindacato.

union foo { 
    struct { 
     uint8_t a : 4; 
     uint8_t b : 4; 
     uint8_t c : 4; 
     uint8_t d : 4; 
     uint16_t e; 
    }; 
    uint32_t allfields; 
}; 

int main(void) { 
    union foo a; 

    a.allfields = 0; 
    a.b = 3; 

    return 0; 
} 
Problemi correlati