C initializer element is not constant - pointers in struct - c

Code snippets appear below
/// System Parameters for the gateway
typedef struct {
bool mobile_gateway; // true = GPS receiver used, else false
uint16_t gw_ordinal_number; // Starting at 1, the ordinal gateway number
} CONFIG_SYSTEM_PARMS;
// Data types for the system parameters
typedef enum {
CFGPARM_TYPE_BOOL,
CFGPARM_TYPE_UINT,
CFGPARM_TYPE_INT,
CFGPARM_TYPE_DOUBLE,
CFGPARM_NUM_TYPES
} CONFIG_PARM_DATA_TYPES;
// These mnemonic names and data types correspond to the system parameters
#define SYS_PARM_MOBILE_GATEWAY_MNEM "MOBILEGW"
#define SYS_PARM_GATEWAY_NUMBER_MNEM "GWNUM"
#define SYS_PARM_MOBILE_GATEWAY_TYPE CFGPARM_TYPE_BOOL
#define SYS_PARM_GATEWAY_NUMBER_TYPE CFGPARM_TYPE_UINT
typedef struct {
char FILLER; // TODO - Define User Parms later...
} CONFIG_USER_PARMS;
static const uint16_t TOTAL_CONFIG_PARM_BYTESIZE = sizeof(CONFIG_SYSTEM_PARMS) + sizeof(CONFIG_USER_PARMS);
typedef struct {
const char *sysparm_mnemonic;
CONFIG_PARM_DATA_TYPES sysparm_data_type;
void *sysparm_data_ptr;
} CONFIG_PARM_LOOKUP_TABLE;
// ****************************************
static LT_LOGGER_DATA gateway_log_data;
static CONFIG_SYSTEM_PARMS *config_sys_parms_ptr = &gateway_log_data.config_system_parms;
// **************************************************
// Lookup table for the System Parms
//
// CAA: This is a stinking mess - There is no easy way to define &gateway_log_data.config_system_parms
// outside of the following initialization, so the result is more verbose than it should be
static const CONFIG_PARM_LOOKUP_TABLE config_parm_lookup_table[] = {
{ SYS_PARM_MOBILE_GATEWAY_MNEM, SYS_PARM_MOBILE_GATEWAY_TYPE, &config_sys_parms_ptr->mobile_gateway},
{ SYS_PARM_GATEWAY_NUMBER_MNEM, SYS_PARM_GATEWAY_NUMBER_TYPE, &gateway_log_data.config_system_parms.gw_ordinal_number},
// FILLER to mark end of list
{ "", 0, NULL}
};
The question is this:
Why, am I getting the error : initializer element is not constant (near initialization for 'config_parm_lookup_table[0].sysparm_data_ptr')
when the initializer for config_parm_lookup_table[1].sysparm_data_ptr is effectively using the same construct?
Obviously, I have a work-around, but it seems verbose.

Related

C Macro get token value instead of token name

Please see the code snipped, in c, below and look at the comments. Is there anyway to make this possible? Does the preprocessor already know that spn_1 = 18? Is there anyway to use the value of spn_1 as a token name?
#define TEST_M(_spn) struct astruct _test_struct_##_spn = { .spn = _spn, };
enum spns {
spn_1 = 18,
};
struct astruct {
int spn;
};
TEST_M(spn_1)
// What I want:
// struct astruct _test_struct_18 = { .spn = 18, };
// What I get:
// struct astruct _test_struct_spn_1 = { .spn = 18, };
// I can do, but I want attach a name to 18:
// TEST_M(18)
Since you want the preprocessor to replace a token by its value, you need the preprocessor for this. So the first step is to use #define instead of an enumeration.
But because of the sequence that macros are expanded, the second step is to use an intermediate macro.
#define TEST_M2(_spn) struct astruct _test_struct_##_spn = { .spn = _spn, };
#define TEST_M(_spn) TEST_M2(_spn)
#define SPN_1 18
struct astruct {
int spn;
};
TEST_X(SPN_1)
TEST_X(18)
This also works with literal numbers.
With GCC you can check the resulting source if you use its option "-E".

Initialize union inside of struct: cannot find why Missing brace around initializer

I am trying to initialize properly this struct:
typedef struct
{
TU_ApplicationData uApplicationData;
TS_SHA_Padding sSHA_Padding;
TU_ApplicationNonVolatileData uApplicationNonVoltatileData;
TS_SHA_Digest sSHA_Digest;
}TS_ApplicationFooter;
As you can see, it is composed with other structure:
typedef struct
{
uint32_t u32ApplicationVersion_Major;
uint32_t u32ApplicationVersion_Minor;
fpJumpHandler fpApplicationJumpHandler;
uint32_t u32BootApplicationStartAddress;
uint32_t u32BootApplicationAllocationSize;
uint32_t u32UserApplicationStartAddress;
uint32_t u32UserApplicationAllocationSize;
}TS_ApplicationData;
typedef union
{
uint32_t au32ApplicationData[32];
TS_ApplicationData sApplicationData;
}TU_ApplicationData;
typedef struct
{
uint32_t u32SHA_1PaddingBytes[16];
}TS_SHA_Padding;
typedef struct
{
uint8_t u8ApplicationNonVoltatileData[256];
}TU_ApplicationNonVolatileData;
typedef struct
{
uint32_t au32ApplicationHashTag[16];
}TS_SHA_Digest;
I cannot find the proper way to initialize the TS_ApplicationFooter structure. The best way that I have is the following, but it returns me the warning: "missing braces around initializer [-Wmissing-braces]".
const TS_ApplicationFooter sUserApplicationFooter =
{ /* Warning point here */
.uApplicationData=
{
.au32ApplicationData={0},
.sApplicationData=
{
.u32ApplicationVersion_Major=U32_USB_CDC_USER_APP_SW_RELEASE_MAJOR_VERSION,
.u32ApplicationVersion_Minor=U32_USB_CDC_USER_APP_SW_RELEASE_MINOR_VERSION,
.fpApplicationJumpHandler=NULL,
.u32BootApplicationStartAddress=U32_BOOT_LOADER_APPLICATION_START_ADDRESS,
.u32BootApplicationAllocationSize=U32_BOOT_LOADER_APPLICATION_ALLOCATED_SIZE,
.u32UserApplicationStartAddress=U32_USER_APPLICATION_START_ADDRESS,
.u32UserApplicationAllocationSize=U32_USER_APPLICATION_ALLOCATED_SIZE
}
},
.sSHA_Padding={0},
.uApplicationNonVoltatileData={0},
.sSHA_Digest={0}
};
Do you have any idea on how I could initialize this structure without having any warning of this kind ?
You should add extra braces around the last three members to appease GCC:
...
.sSHA_Padding={{0}},
.uApplicationNonVoltatileData={{0}},
.sSHA_Digest={{0}}
};
This might be a bug in GCC. Clang does not show this warning, even if compiled with -Wall -W -Wmissing-braces -pedantic.
Alternatively, since as soon as you initialize one member member of a struct, all other members that are not explicitly initialized are initialized to zero, you can just omit them.
Furthermore, you should only initialize exactly one member of a union! I recommend you rewrite the whole initialization like so:
const TS_ApplicationFooter sUserApplicationFooter =
{
.uApplicationData =
{
.sApplicationData =
{
.u32ApplicationVersion_Major = U32_USB_CDC_USER_APP_SW_RELEASE_MAJOR_VERSION,
.u32ApplicationVersion_Minor = U32_USB_CDC_USER_APP_SW_RELEASE_MINOR_VERSION,
.u32BootApplicationStartAddress = U32_BOOT_LOADER_APPLICATION_START_ADDRESS,
.u32BootApplicationAllocationSize = U32_BOOT_LOADER_APPLICATION_ALLOCATED_SIZE,
.u32UserApplicationStartAddress = U32_USER_APPLICATION_START_ADDRESS,
.u32UserApplicationAllocationSize = U32_USER_APPLICATION_ALLOCATED_SIZE
}
},
};

What does `static int (*const array[SIZE_ARRAY]...)(int a) = {[SOMETHING]=something}` mean in C?

I'm having a hard time interpreting the following C code:
static int (* const net_client_init_fun[NET_CLIENT_DRIVER__MAX])(
const Netdev *netdev,
const char *name,
NetClientState *peer, Error **errp) = {
[NET_CLIENT_DRIVER_NIC] = net_init_nic,
#ifdef CONFIG_SLIRP
[NET_CLIENT_DRIVER_USER] = net_init_slirp,
#endif
[NET_CLIENT_DRIVER_TAP] = net_init_tap,
[NET_CLIENT_DRIVER_SOCKET] = net_init_socket,
#ifdef CONFIG_VDE
[NET_CLIENT_DRIVER_VDE] = net_init_vde,
#endif
#ifdef CONFIG_NETMAP
[NET_CLIENT_DRIVER_NETMAP] = net_init_netmap,
#endif
#ifdef CONFIG_NET_BRIDGE
[NET_CLIENT_DRIVER_BRIDGE] = net_init_bridge,
#endif
[NET_CLIENT_DRIVER_HUBPORT] = net_init_hubport,
#ifdef CONFIG_VHOST_NET_USER
[NET_CLIENT_DRIVER_VHOST_USER] = net_init_vhost_user,
#endif
#ifdef CONFIG_L2TPV3
[NET_CLIENT_DRIVER_L2TPV3] = net_init_l2tpv3,
#endif
};
this looks like a function pointer declaration, but then it does = {...} which I don't recognize. Is also does [] inside.
What this is exactly?
It might be easier to understand by using a type-alias:
// Define a type-alias for a pointer to a function
typedef int (*net_client_init_fun_type)(const Netdev *, const char *, NetClientState *, Error **);
// Define an array of pointers to functions
static net_client_init_fun_type net_client_init_fun[NET_CLIENT_DRIVER__MAX] = { ... }
It still requires knowledge about function-pointers and how they are declared/defined, but it will make the array declaration much easier to read.
The array initialization list uses designated array initialization.
When you have a line like:
[NET_CLIENT_DRIVER_NIC] = net_init_nic
in the array initialization list, it means that the index NET_CLIENT_DRIVER_NIC of the array will be initialized to net_init_nic.

error: initializer element is not constant in C [duplicate]

This question already has answers here:
Error "initializer element is not constant" when trying to initialize variable with const
(8 answers)
Closed 3 years ago.
Here i am trying to make state machine where FsmHdlr should call a appropriate function based on state and event. What i am getting the above error. How to resolve this.
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
}
};
It sounds like you don't actually want to call the function during initialization (which you can't do for static storage variables anyway, as you've discovered). It sounds like you are building a dispatch table. What you want is called a function pointer.
This how one uses function pointers:
int foo(void) { ... }
int main(void) {
int (*bar)(void) = foo;
bar(); // Calls foo
}
Since the parameters vary based on the type of the event, a 2d array doesn't make much sense. I'd use the following in your case:
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 },
};
Later:
fsm_hdlrs_by_state[state].fsm_req_hdlr();
fsm_hdlrs_by_state[state].fsm_rsp_hdlr(param_rsp);
You could declare pointer to FsmHdlr[MAX_STATE][MAX_EVENT] as a global variable.
S16 (*FsmHdlr)[MAX_STATE][MAX_EVENT] = NULL;
Somewhere in main function allocate the memory to the global pointer as below.
FsmHdlr = malloc(sizeof(S16 [MAX_STATE][MAX_EVENT]));
Then use memcpy to copy array compound literal as below.
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)
}
})
);
And dereference as below,
(*FsmHdlr)[0][0];//to access 1st element
(*FsmHdlr)[0][1];//to access 2nd element
You cannot initialise array during declaration using values, what are unknown while compilation.
And, your initialization values are values returned by handleParamReqEvt() and handleParamRspEvt(...), what are unknown.
I suppose that you are thinking about pointers to these functions, nor function values.
So, you should use function names instead of function calls, like below:
S16 FsmHdlr[MAX_STATE][MAX_EVENT] =
{
{
/* PHY_STATE_IDLE */
handleParamReqEvt, //initializer element is NOW constant
handleParamRspEvt //initializer element is NOW constant
}
};
Unfortunately, this will not compile because of wrong array type - now it is not S16[][] (or S16**) like before.
Additionaly, both pointers are pointers of different types:
- first is S16 ( * )();
- second is S16 ( * )(param_resp*);
Fortunately, you can store them both as void* (pointer to anything), but remember that you MUST PROPERLY CAST them before usage.
For cast simplification you can declare the types of these function using typedef directive.
So, the final form of declaration+initialization and usage will be:
// 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

Incorrect initialization of a structure instance with data from const char *[][]

I obtained the following compilation error:
error: initializer element is not constant
while using this code (divided into 3 files, as follows):
File 1
This array is used to easily switch between language versions of menu.
#define LANG_EN 0
#define LANG_PL 1
#define LANGUAGES 2
const char *const message[][LANGUAGES] = {
#define MSG_INTRO 0
/*0*/ { "Hello", "Witamy" },
#define MSG_MENU1 1
/*1*/ { "Option1", "Opcja1" },
#define MSG_MENU2 2
/*2*/ { "Option2", "Opcja2" },
};
File 2
This file contains,among others, the definition of the structure used:
struct _menuitem
{
const char *const text;
int action;
};
struct _menuitem const menu;
File 3
In main.c I initialize the structure:
#define PGM_STR(X) ((const char[]) { X })
const struct _menuitem const menu = {PGM_STR(message[MSG_INTRO][LANG_PL]), 0};
When I put any string in quotes (like "Testest") under PGM_STR macro then everything is fine.
Q: How should I initialize the struct with string data from the
const char *const message[][LANGUAGES]
so that it remains inline as shown above?
What am I doing wrong?
I know there are a lot of topics concerning this compilation error, but none of them actually concerns this type of array-structure combination.

Resources