Abirami Sridharan
Abirami Sridharan

Reputation: 29

Can static_cast work for bit fields?

Hi does static cast work for bit fields?. Because here i have created a bit field of 32 bit Long data and i am trying to cast it to u32.

void CO2_SpiDriver::CreateBuffer() {
    //#[ operation CreateBuffer()
    typedef struct scr_t
     {
         union {
            u32 data;
             struct {
                 u8 CRC : 4; 
                 u16 Datatosend : 16;
                 u8 DataLengthCode : 2;
                 u8 AddressReg : 4;
                 u8 ReadandWrite : 1;
                 u8 InstrucCode : 3;
                 u8 ExtChipId : 2;
             };
         };
     } scr_t;  

     //set of data bits
     scr_t se;
     se.CRC = 0x00;   //CRC BITS 0 to 3
     se.Datatosend = 0x0000000000000000;  //Data bits 19 to 4
     se.DataLengthCode = 0x00; //DLC bits 21 and 20
     se.AddressReg = 0x00;     // SMP580 registers to access 25-22
     se.ReadandWrite = 0x01;  //Read|Write Reg 26
     se.InstrucCode = 0x5;    //InstrCode 29-27
     se.ExtChipId = 0x2;      //ExtChipId 31-30       

     static_cast<u32>(se)

But here i am getting an error that scr_t cannot be casted to u32. Can anyone give some suggestions

Upvotes: 0

Views: 1240

Answers (1)

YSC
YSC

Reputation: 40080

In C++, only one of the fields of an union is active at any time. The only portable way to reinterpret a memory layout is to use std::memcpy:

struct bf {
    u8 CRC : 4; 
    u16 Datatosend : 16;
    u8 DataLengthCode : 2;
    u8 AddressReg : 4;
    u8 ReadandWrite : 1;
    u8 InstrucCode : 3;
    u8 ExtChipId : 2;
};

bf se;
se.CRC = 0x00;   //CRC BITS 0 to 3
se.Datatosend = 0x0000000000000000;  //Data bits 19 to 4
se.DataLengthCode = 0x00; //DLC bits 21 and 20
se.AddressReg = 0x00;     // SMP580 registers to access 25-22
se.ReadandWrite = 0x01;  //Read|Write Reg 26
se.InstrucCode = 0x5;    //InstrCode 29-27
se.ExtChipId = 0x2;      //ExtChipId 31-30  

u32 se_as_u32;
static_assert(sizeof(se_as_u32) <= sizeof(se), "UB detector"); // avoid reading buffer overflow (see explanation below)
std::memcpy(&se_as_u32, &se, sizeof(se_as_u32));

Note: I've added the line

static_assert(sizeof(se_as_u32) <= sizeof(se), "UB detector");

in order to protect se to be read outside of its "bounds":

std::memcpy(&se_as_u32, &se, sizeof(se_as_u32));

This reads sizeof(u32) (probably 4) bytes from se. In the eventuality that se was smaller than 4 bytes long, memcpy would read "outside of it", this is a kind of buffer overflow and result in undefined behaviour (this is bad). In the case where the inequality was not respected (sizeof(se_as_u32) > sizeof(se)), a merciful abort() would be called and the program would promptly crash instead of maybe working for a time and destroy the production one day.

Upvotes: 4

Related Questions