Search code examples
ccastingembeddedbit-fields

How to cast struct to uint8_t (error: conversion to non-scalar type requested)


I need to store the state of 8 relays in EEPROM. I didn't want to bother with shifting and I like using bitfields. So I wanted to define them like this:

typedef struct{
    uint8_t RELAY0_STATE:1;
    uint8_t RELAY1_STATE:1;
    uint8_t RELAY2_STATE:1;
    uint8_t RELAY3_STATE:1;
    uint8_t RELAY4_STATE:1;
    uint8_t RELAY5_STATE:1;
    uint8_t RELAY6_STATE:1;
    uint8_t RELAY7_STATE:1;
}relay_nvm_t;

relay_nvm_t   relay_nvm;

In my main code flow, I set the state of each relay using relay_nvm variable. Example

...
if(something)
{
    relay_nvm.RELAY0_STATE = 1;
    relay_nvm.RELAY1_STATE = 0;
    relay_nvm.RELAY2_STATE = 1;
    relay_nvm.RELAY3_STATE = 0;
    relay_nvm.RELAY4_STATE = 1;
    relay_nvm.RELAY5_STATE = 1;
    relay_nvm.RELAY6_STATE = 0;
    relay_nvm.RELAY7_STATE = 1;
}

Then finally when I need to read/write to EEPROM, I just cast relay_nvm to uint8_t to read/write one byte to EEPROM. But I get error: conversion to non-scalar type requested error. Below are my functions.

static void NVM_Relay_Read(void)
{
    relay_nvm = (relay_nvm_t)NVM_ReadEepromByte(NVM_RELAY_INDEX);
}

static void NVM_Relay_Write(relay_nvm_t rs)
{
    NVM_WriteEepromByte(NVM_RELAY_INDEX, (uint8_t)rs);
}

Is there any way we can get over this error? I thought I could just do it by typecasting. The use of bitfields makes my job very easy and makes the code easy to understand.

I know that bitfields may not be safe in this case due to the padding but I think I can get over it using POP-PUSH (is it worth?)


Solution

  • I see more ways to handle this:

    1. Use union.

    2. Use pointer type-cast: *((uint8_t*)&relay_nvm)

    3. Use uint8_t:

        uint8_t relay_nvm;
        #define RELAY0_MASK 1
        #define RELAY1_MASK 2
        #define RELAY2_MASK 4
        ...
        #define RELAY7_MASK 128
    
        // set exact relays state:
        relay_nvm = RELAY0_MASK | RELAY2_MASK | RELAY4_MASK | ... ;
    
        // set single relay (others left unchanged):
        relay_nvm |= RELAY2_MASK;
    
        // clear single relay (others left unchanged):
        relay_nvm &= ~RELAY2_MASK;
    
        // check current state of a relay:
        if (relay_nvm & RELAY2_MASK) { ... }