Search code examples
c++gccstructvolatile

volatile struct vs. typecast


I have the following declarations in my code:

h file:

typedef struct {
    bool qualified : 1;
    bool running : 1;
} calibration_state_t;

calibration_state_t get_calibration_state();

cpp file:

volatile calibration_state_t calibration_state = {false ,false};

The function

calibration_state_t get_calibration_state() {
    return *(calibration_state_t *)&calibration_state;
}

compiles. However if I replace the return statement with

return (calibration_state_t)calibration_state;

It fails with

dcf77.cpp: In function ‘DCF77_Frequency_Control::calibration_state_t DCF77_Frequency_Control::get_calibration_state()’:
dcf77.cpp:2923:37: error: no matching function for call to ‘DCF77_Frequency_Control::calibration_state_t::calibration_state_t(volatile DCF77_Frequency_Control::calibration_state_t&)’
dcf77.h:204:7: note: candidates are: DCF77_Frequency_Control::calibration_state_t::calibration_state_t()
dcf77.h:204:7: note:                 DCF77_Frequency_Control::calibration_state_t::calibration_state_t(const DCF77_Frequency_Control::calibration_state_t&)

The compiler is avr-gcc but I suspect this does not matter. Why does the compiler fail to compile the type cast? How would I get to the desired return value in a clean way?


Solution

  • What is the desired behavior exactly? Must ordering be preserved, for example? If something else sets qualified and then running, is it okay to get the old value of qualified but the new value of running?

    Because the structure is volatile, operations on it are part of the visible behavior of the program. That is, this:

    calibration_state_t get_calibration_state()
    {
        calibration_state_t ret;
        ret.qualified = calibration_state.qualified;
        ret.running = calibration_state.running;
        return ret;
    }
    

    Is not the same as:

    calibration_state_t get_calibration_state()
    {
        calibration_state_t ret;
        ret.running = calibration_state.running;
        ret.qualified = calibration_state.qualified;
        return ret;
    }
    

    So, you have to code what you want. How can the compiler know what behavior you want? You got some behavior by lying to the compiler, but I doubt it's the behavior you want.