cembeddedfsm

"assignment of read-only member" error when assigning to non const member of a struct


I am trying to create a FSM in C. I am using a variation of the STATE pattern for C that is explained here. The problem is that I am in the embedded world and they make me comply with some safety-critical rules. One of these rules says that I can't use non-const pointers to functions, so I have created my fsm like this:

typedef struct tFsm* tFsmPtr;

/* PLEASE NOTE: This is a non const struct with its member
 * being a const pointer to a function.  */
typedef struct
{
    void (*const raise)(tFsmPtr);
} tEvent;

struct tFsm
{
    /* Because the tEvent type is non const,
     * I can modify these fields */
    tEvent start;
    tEvent started;
    tEvent stop;
    tEvent stopped;
};

static void DefaultInvalidEventCallback(tFsmPtr fsm)
{
    /* Raise an error */
}

static struct tFsm m_fsm = {
    .start   = { .raise = &DefaultInvalidEventCallback },
    .started = { .raise = &DefaultInvalidEventCallback },
    .stop    = { .raise = &DefaultInvalidEventCallback },
    .stopped = { .raise = &DefaultInvalidEventCallback }
};

No errors so far. The problem is that when I try to modify any field of the struct tFsm, it complains. For example this code:

void ResetFsm( tFsmPtr fsm )
{
    fsm->start       = (tEvent){ .raise = &DefaultInvalidEventCallback };
    fsm->started     = (tEvent){ .raise = &DefaultInvalidEventCallback };
    fsm->stop        = (tEvent){ .raise = &DefaultInvalidEventCallback };
    fsm->stopped     = (tEvent){ .raise = &DefaultInvalidEventCallback };
}

The compiler complains saying that:

prog.c: In function 'ResetFsm':
prog.c:32:22: error: assignment of read-only member 'start'
     fsm->start       = (tEvent){ .raise = &DefaultInvalidEventCallback };
                      ^
prog.c:33:22: error: assignment of read-only member 'started'
     fsm->started     = (tEvent){ .raise = &DefaultInvalidEventCallback };
                      ^
prog.c:34:22: error: assignment of read-only member 'stop'
     fsm->stop        = (tEvent){ .raise = &DefaultInvalidEventCallback };
                      ^
prog.c:35:22: error: assignment of read-only member 'stopped'
     fsm->stopped     = (tEvent){ .raise = &DefaultInvalidEventCallback };
                      ^

My questions are: Could you please tell me why the compiler complains here? Is there a way of using const pointers to functions here?

Thanks in adavance.


Solution

  • Member raise of struct tEvent, is defined with const:

    void (*const raise)(tFsmPtr);
    

    This means that only initialization of the entire struct is possible:

    tEvent s = { DefaultInvalidEventCallback };
    

    but assignment of the entire struct is not:

    tEvent a;
    a = s;
    

    This of course holds true for any struct which has the struct tEvent as its member, for example: struct tFsm, as shown in your example