【问题标题】:"assignment of read-only member" error when assigning to non const member of a struct分配给结构的非 const 成员时出现“只读成员分配”错误
【发布时间】:2016-05-01 14:30:05
【问题描述】:

我正在尝试在 C 中创建 FSM。我正在使用 C 的 STATE 模式的变体,已解释为 here。问题是我在嵌入式世界中,它们让我遵守一些安全关键规则。其中一条规则说我不能使用指向函数的非常量指针,所以我创建了这样的 fsm:

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 }
};

到目前为止没有错误。问题是当我尝试修改struct tFsm 的任何字段时,它会抱怨。例如这段代码:

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

编译器抱怨说:

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 };
                      ^

我的问题是: 你能告诉我为什么编译器在这里抱怨吗? 有没有办法在这里使用指向函数的 const 指针?

提前致谢。

【问题讨论】:

  • 因为const in tEvent?....

标签: c embedded fsm


【解决方案1】:

struct tEvent 的成员 raise 用 const 定义:

void (*const raise)(tFsmPtr);

这意味着只能初始化整个结构:

tEvent s = { DefaultInvalidEventCallback };

但整个结构的赋值不是:

tEvent a;
a = s;

这当然适用于任何以结构 tEvent 作为其成员的结构,例如:struct tFsm,如您的示例所示

【讨论】:

    【解决方案2】:

    对于任何具有const 成员的结构,您只能在初始化结构时设置该成员。您不能在运行时更改它,原因与您不能这样做的原因相同:

    const int x=1; 
    x=2;
    

    您已经创建了一个immutable object

    由于不允许使用非常量函数指针,函数ResetFsm 没有任何意义,需要删除。没有办法把它写得有意义。

    你可以做的是:

    struct tFsm CreateDefaultFsm (void)
    {
      return (struct tFsm)
      {
        .start    = (tEvent){ .raise = &DefaultInvalidEventCallback },
        .started  = (tEvent){ .raise = &DefaultInvalidEventCallback },
        .stop     = (tEvent){ .raise = &DefaultInvalidEventCallback },
        .stopped  = (tEvent){ .raise = &DefaultInvalidEventCallback },
      };
    }
    

    您还可以创建类似的复制函数等。所有在结构上工作的函数都必须创建它的新副本。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-09-10
      • 2012-08-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-08-03
      • 1970-01-01
      相关资源
      最近更新 更多