【问题标题】:error: initializer element is not constant in C [duplicate]错误:初始化元素在 C 中不是常量 [重复]
【发布时间】:2020-03-27 18:37:18
【问题描述】:

在这里,我正在尝试制作状态机,其中 FsmHdlr 应该根据状态和事件调用适当的函数。我得到了上述错误。如何解决这个问题。

   S16 handleParamReqEvt(void)
    {
      /* doing something */
      RETVALUE(ROK);    
    }

    S16 handleParamRspEvt(param_resp *paramRsp) 
    {
      /* doing something */
      RETVALUE(ROK);    
    }

    typedef enum{
      IDLE,
      CONFIGURED,
      MAX_STATE
    }STATE;

    /* Events in CL */
    typedef enum{
      PARAM_REQ,
      PARAM_RSP 
      MAX_EVENT
    }EVENT;

    param_resp *paramMsg;

    S16 FsmHdlr[MAX_STATE][MAX_EVENT] = 
    {
      {
        /* PHY_STATE_IDLE */
        handleParamReqEvt(),           //error :initializer element is not constant
        handleParamRspEvt(paramMsg)    //error: initializer element is not constant
      }
    };

【问题讨论】:

  • FsmHdlr 这是全局变量吗?否则这个错误没有意义。请提供minimal reproducible example
  • 什么是S16RETVALUE 是什么? ROK 是什么?
  • 是的 FsmFdlr 在这里是全局的。由于代码很长,我无法粘贴整个 S16 是 int 类型的 Retvalue (rok) 是返回 0
  • 您是在尝试编译遗留代码还是这些是您的本地更改?对我来说FsmHdlr 应该是一个函数指针或函数指针数组,取决于输入。
  • @MAMTHASRI 至少在c 中是不可能的,除非你存储函数指针而不是它的返回值。

标签: c


【解决方案1】:

您可以将指向FsmHdlr[MAX_STATE][MAX_EVENT] 的指针声明为全局变量。

S16 (*FsmHdlr)[MAX_STATE][MAX_EVENT] = NULL;

main 函数中的某处将内存分配给全局指针,如下所示。

FsmHdlr = malloc(sizeof(S16 [MAX_STATE][MAX_EVENT]));

然后使用memcpy 复制数组复合文字如下。

   memcpy(FsmHdlr,
         (S16 [MAX_STATE][MAX_EVENT])    {
             {
                 /* PHY_STATE_IDLE */
                handleParamReqEvt(), handleParamRspEvt(paramMsg) 
             }
           },
         sizeof((S16 [MAX_STATE][MAX_EVENT])    {
             {
                 /* PHY_STATE_IDLE */
                handleParamReqEvt(), handleParamRspEvt(paramMsg) 
             }
           })
   );

并解引用如下,

(*FsmHdlr)[0][0];//to access 1st element
(*FsmHdlr)[0][1];//to access 2nd element

【讨论】:

    【解决方案2】:

    听起来您实际上并不想在初始化期间调用该函数(正如您所发现的那样,无论如何您都不能对静态存储变量执行此操作)。听起来您正在构建一个调度表。你想要的是一个函数指针。

    这是使用函数指针的方式:

    int foo(void) { ... }
    
    int main(void) {
       int (*bar)(void) = foo;
       bar();  // Calls foo
    }
    

    由于参数根据事件的类型而有所不同,因此二维数组没有多大意义。我会在你的情况下使用以下内容:

    S16 fsm_hdrl_idle_param_req(void)                { ... }
    S16 fsm_hdrl_idle_param_rsp(ParamRsp *param_rsp) { ... }
    S16 fsm_hdrl_conf_param_req(void)                { ... }
    S16 fsm_hdrl_conf_param_rsp(ParamRsp *param_rsp) { ... }
    
    typedef S16 (*FsmReqHdlr)(void);
    typedef S16 (*FsmRspHdlr)(ParamRsp*);
    
    typedef struct {
       FsmReqHdlr fsm_req_hdlr;
       FsmRspHdlr fsm_rsp_hdlr;
    } FsmHdlrs;
    
    FsmHdlrs fsm_hdlrs_by_state[MAX_STATE] = {
       { fsm_hdrl_idle_param_req, fsm_hdrl_idle_param_rsp },
       { fsm_hdrl_conf_param_req, fsm_hdrl_conf_param_rsp },
    };
    

    稍后:

    fsm_hdlrs_by_state[state].fsm_req_hdlr();
    
    fsm_hdlrs_by_state[state].fsm_rsp_hdlr(param_rsp);
    

    【讨论】:

    • OP 有两个具有两个不同签名的函数,我认为你的方法不适合。
    • @kiran Biradar,我已经更新了我的答案。
    【解决方案3】:

    您不能在声明期间使用值初始化数组,编译时未知。 而且,您的初始化值是由 handleParamReqEvt() 和 handleParamRspEvt(...) 返回的值,这是未知的。 我想您正在考虑指向这些函数的指针,也不是函数值。 因此,您应该使用函数名称而不是函数调用,如下所示:

    S16 FsmHdlr[MAX_STATE][MAX_EVENT] = 
    {
      {
        /* PHY_STATE_IDLE */
        handleParamReqEvt,   //initializer element is NOW constant
        handleParamRspEvt    //initializer element is NOW constant
      }
    };
    

    不幸的是,由于数组类型错误,这将无法编译 - 现在它不像以前那样 S16[][](或 S16**)。 另外,两个指针都是不同类型的指针: - 首先是 S16 ( * )(); - 第二个是 S16 ( * )(param_resp*); 幸运的是,您可以将它们都存储为 void*(指向任何东西的指针),但请记住,在使用之前您必须正确地转换它们。 为了简化转换,您可以使用 typedef 指令声明这些函数的类型。

    所以,声明+初始化和使用的最终形式是:

    // declaration + initialisation of array
    void* FsmHdlr[MAX_STATE][MAX_EVENT] = 
    {
      {
        /* PHY_STATE_IDLE */
        handleParamReqEvt,
        handleParamRspEvt
      }
    };
    
    // declaration of types
    typedef S16 (*reqEvt_ptr)();            //signature of handleParamReqEvt()
    typedef S16 (*rspEvt_ptr)(param_resp*); //signature of handleParamRspEvt(param_resp*)
    
    // usage:
    // handleParamReqEvt
    reqEvt_ptr reqEvt = (reqEvt_ptr)FsmHdlr[/* index here */][PARAM_REQ]; // cast
    S16 reqResult = reqEvt(); // call
    // handleParamRspEvt
    rspEvt_ptr rspEvt = (rspEvt_ptr)FsmHdlr[/* index here */][PARAM_RSP]; // cast
    S16 rspResult = rspEvt(/* pointer to paramMsg here */); // call
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-04-10
      • 2020-06-29
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      • 2012-06-04
      相关资源
      最近更新 更多