Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to assign value to a struct with bit-fields?

Tags:

c++

bit-fields

I have a struct with bit-fields (totally 32 bit width) and I have a 32-bit variable. When I try to assign the variable value to my struct, I got an error:

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;

Do you have any idea how to do it in the shortest way? Thanks

P.S. Of course I have more appropriate value of EAX in real code, but I guess it doesn't affect here.

like image 532
Irina Avatar asked Jun 01 '12 13:06

Irina


4 Answers

You should never rely on how the compiler lays out your structure in memory. There are ways to do what you want with a single assignment, but I will neither recommend nor tell you.

The best way to do the assignment would be the following:

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

And the opposite

static inline uint32_t from_id(struct CPUid *id)
{
    return id->Stepping
         | id->Model << 4
         | id->FamilyID << 8
         | id->Type << 12
         | id->Reserved1 << 14
         | id->ExtendedModel << 16
         | id->ExtendedFamilyID << 20
         | id->Reserved2 << 28;
}
like image 197
Shahbaz Avatar answered Oct 10 '22 12:10

Shahbaz


Use a union.

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;
}
like image 31
Ben Avatar answered Oct 10 '22 13:10

Ben


Just if somebody´s interested, I´ve got a better solution for my own question:

*(reinterpret_cast<uint32_t *> (&CPUIDoutput)) = CPUIDregsoutput.EAXBuf;
like image 2
Irina Avatar answered Oct 10 '22 12:10

Irina


These are struct members, so you need to assign directly do them, or make sure the RHS of your assignment is a value of type CPUID. Not sure why you expect to be able to assign to the struct from an integer.

The facts that the struct contains bitfields, and that the sum of the bits happens to be the same as the number of bits in the integer you're trying to assign, mean nothing. They're still not compatible types, for assignment purposes.

If this was too vague, consider showing more/better code.

like image 1
unwind Avatar answered Oct 10 '22 12:10

unwind