this is the definition and declaration of the structure
typedef struct ST_accountsDB_t
{
float balance;
uint8_t primaryAccountNumber[20];
}ST_accountsDB_t;
ST_accountsDB_t accountsDB[255];
then I started filling it
accountsDB[0].balance = 20000;
accountsDB[0].primaryAccountNumber[20] = "1234567891234567";
accountsDB[1].balance = 50000;
accountsDB[1].primaryAccountNumber[20] = "9872653461728839";
accountsDB[2].balance = 40000;
accountsDB[2].primaryAccountNumber[20] = "6873645738467382";
accountsDB[3].balance = 28000;
accountsDB[3].primaryAccountNumber[20] = "3872634547838276";
accountsDB[4].balance = 3000;
accountsDB[4].primaryAccountNumber[20] = "1283764957873637";
accountsDB[5].balance = 100000;
accountsDB[5].primaryAccountNumber[20] = "3485793029384758";
accountsDB[6].balance = 30000;
accountsDB[6].primaryAccountNumber[20] = "8746330283748393";
this is the normal way to fill a string right ? why isn't it working ? am I missing something ?
You can initialize it when you declare it, using an initialization list.
ST_accountsDB_t accountsDB[255] = {
{20000, "1234567891234567"},
{50000, "9872653461728839"},
...
};
If you want to fill it in after declaring it, use strcpy() to copy strings.
strcpy(accountsDB[0].primaryAccountNumber, "1234567891234567");
Even though uint8_t is equivalent to unsigned char, it's conventional to use char arrays to declare strings.
typedef struct ST_accountsDB_t
{
float balance;
unsigned char primaryAccountNumber[20];
}ST_accountsDB_t;
If you initialize the variable:
ST_accountsDB_t accountsDB[255] = {
{ 20000.0, "1234567891234567", },
{ 50000.0, "9872653461728839", },
{ 40000.0, "6873645738467382", },
/* ...*/ };
In the code (but not initialization) using compound literals.
accountsDB[x] = (ST_accountsDB_t){ 40000.0, "6873645738467382", };
You cant assign arrays. You need to copy them yourself. If it is a string you need to use strcpy function.
strcpy(accountsDB[0].primaryAccountNumber,"1234567891234567");
As others have told you, use an initializer list. However, when doing so also consider using designated initializers to make the code safer and more readable:
ST_accountsDB_t accountsDB[] =
{
{ .balance = 20000, .primaryAccountNumber = "1234567891234567" },
{ .balance = 50000, .primaryAccountNumber = "9872653461728839" },
/* and so on */
};
You can also add a compile-time check to ensure data integrity:
#define ACCOUNTS_DB_SIZE 255
...
_Static_assert(sizeof accountsDB/sizeof accountsDB[0] == ACCOUNTS_DB_SIZE,
"Wrong size: accountsDB");
You want the compiler to fill-in a character array from a string. Don't make it difficult for everyone. Copy/paste/adapt is NOT the way to develop code.
typedef struct ST_accountsDB_t {
float balance;
char primaryAccountNumber[20]; // NB char, not uint8_t
} ST_accountsDB_t;
ST_accountsDB_t accountsDB[] = {
{ 20000.0, "1234567891234567", },
{ 50000.0, "9872653461728839", },
{ 40000.0, "6873645738467382", },
{ 28000.0, "3872634547838276", },
{ 3000.0, "1283764957873637", },
{ 100000.0, "3485793029384758", },
{ 30000.0, "8746330283748393", },
};
And, using the dimension 255 suggests you've spent the time counting... The compiler counts more accurately than most humans.
Related
I'm an avid embedded c programmer. I recently started working with the ESP IDF framework to program the ESP32. Even though I think that the following code is initializing a struct within a struct (not sure); but for some reason, I cannot grasp how and why there is just a ".mode" rather than the struct's name within gpio_config_t + ".mode". This is just an example but there are several instances of similar types of initialization.
for example:
typedef struct example_struct{
int mode;
int pull_up_en;
.
.
}example_struct;
typedef struct gpio_config_t
{
example_struct test;
} gpio_config_t;
Shouldn't the initialization be done the following way?
gpio_config_t io_test_config =
{
test.mode = 3;
test.pull_up_en = 1;
etc
};
Can someone please clarify this?
The actual type of initialization I'm referring to:
gpio_config_t io_conf = {
.mode = GPIO_MODE_OUTPUT,
.pull_up_en = 1,
};
The technical term for the notation you're using is designated initializers. The designators always start with either a . or a [, and there are no semicolons in the initializers (until after the } at the end of the initializer). There are many ways that you could initialize that structure, including:
gpio_config_t io_test_config1 =
{
.test.mode = 3, .test.pull_up_en = 1
};
gpio_config_t io_test_config2 =
{
.test = { .mode = 3, .pull_up_en = 1 }
};
gpio_config_t io_test_config3 =
{
{ 3, 1 }
};
gpio_config_t io_test_config4 =
{
3, 1
};
The last one doesn't compile cleanly with GCC when you specify -Wmissing-braces (usually activated by -Wall).
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
I'm using VS2013. The whole program is C, not C++.
I can initialize an "array of strings" like this without any problems:
char titles[4][80] = { "Dad", "Idiot", "Donut Lover", "Fewl" }; // OK!
I have a struct declared like this:
typedef struct
{
char name[80];
char titles[4][80];
} Dude;
When I try to initialize the struct like this:
Dude homer =
{
.name = "Homer",
.titles = { "Dad", "Idiot", "Donut Lover", "Fewl" } // error?
};
I get an "error C2078: too many initializers". This is because of the array initialization- If I remove the .titles = { ... line, the error goes away. Why am I getting this error? Is there a different way to accomplish this type of string initialization within a struct initializer?
If I change the declaration of the struct to look like this
typedef struct
{
char name[80];
char *titles[4];
} Dude;
the error goes away. This is, however, not a change I can make. Other parts of the code base require that the size of this struct is exactly 400 bytes.
Further, I'm quite aware that I could use strcpy to fill in each field, but that does not answer my question.
In C, it's easier to do this:
Dude homer =
{
"Homer",
{ "Dad", "Idiot", "Donut Lover", "Fewl" } // error?
};
Don't know if this works, but you can try:
Dude homer =
{
.name = "Homer",
.titles[] = { "Dad", "Idiot", "Donut Lover", "Fewl" } // error?
};
I'm trying to compile the following C code using IAR EWARM but I'm getting three compilation errors (Error[Pe028]: expression must have a constant value). See below:
#include<stdio.h>
#include<stdlib.h>
#include<stdint.h>
typedef uint8_t I2C_BusIdentifier;
typedef uint8_t I2C_SlaveAddress;
typedef enum {
I2C_BUS_STATE_UNINITIALIZED = 0,
I2C_BUS_STATE_GPIO_HARDWARE_READY,
I2C_BUS_STATE_READY_TO_OPERATE,
} I2C_BusState;
typedef struct BUS_I2C_BUS_INSTANCE_TYPE {
I2C_BusIdentifier BusIdentifer; // 0 for I2C0, 1 for I2C1
I2C_BusState CurrentState; // bus status
} I2C_Bus; // I²C Bus Instance Type, I2C_BusInstanceType
typedef struct DEVICE_I2C_GENERIC {
I2C_Bus* DeviceBusPointer;
I2C_SlaveAddress DeviceAddress;
} I2C_Device;
// inherits from I2C_Device
typedef struct DEVICE_ADC123 {
I2C_Device Device;
} ADC123_Device;
#define NUMBER_OF_I2C_PORTS 2
static I2C_Bus g_I2C_Bus[NUMBER_OF_I2C_PORTS] = {
{ 0, I2C_BUS_STATE_UNINITIALIZED, },
{ 1, I2C_BUS_STATE_UNINITIALIZED, },
};
I2C_Bus* const g_I2C_BusPtr_Port0 = &(g_I2C_Bus[0]);
I2C_Bus* const g_I2C_BusPtr_Port1 = &(g_I2C_Bus[1]);
const ADC123_Device g_Device_ADC123_U14 = {
{ g_I2C_BusPtr_Port0, 0xAE, }, // <--- Error[Pe028]: expression must have a constant value
};
const ADC123_Device g_Device_ADC123_U15 = {
{ g_I2C_BusPtr_Port1, 0x8A, }, // <--- Error[Pe028]: expression must have a constant value
};
const ADC123_Device g_Device_ADC123_U9 = {
{ g_I2C_BusPtr_Port1, 0xAA, }, // <--- Error[Pe028]: expression must have a constant value
};
#define NUMBER_OF_ADC123_DEVICES 3
const ADC123_Device* g_ADC123_Array[NUMBER_OF_ADC123_DEVICES] = {
&g_Device_ADC123_U14,
&g_Device_ADC123_U15,
&g_Device_ADC123_U9,
};
int main(void)
{
while(1);
}
However, everything compiles OK if I use the g_I2C_Bus addresses directly instead of through the g_I2C_BusPtr_PortX pointers:
const ADC123_Device g_Device_ADC123_U14 = {
{ &(g_I2C_Bus[0]), 0xAE, },
};
const ADC123_Device g_Device_ADC123_U15 = {
{ &(g_I2C_Bus[1]), 0x8A, },
};
const ADC123_Device g_Device_ADC123_U9 = {
{ &(g_I2C_Bus[1]), 0xAA, },
};
I want to use the const pointers (g_I2C_BusPtr_Port0, g_I2C_BusPtr_Port1) because they are extern'd in a .h file, whereas the array (g_I2C_Bus[]) will not be exposed globally but static in a specific .c file.
Why is the compuler unhappy about this when the definitions/values should be equivalent since they reference the same thing?
This is a limitation with C language. Values of variables, like
int const a = 1;
cannot be used in constant expressions, like as initializers:
int b = a; /* Will not work */
Not even with const qualifier. Reasoning is that compiler cannot know values of variables, even if it would seem completely trivial. Variable with const is not a constant in C, it's only variable which cannot be changed by you.
Addresses of global variables are a different matter. Linker complete control where these variables are located, and can use the same information for initializers.
Work-around is to use preprocessor:
#define g_I2C_BusPtr_Port0 (&(g_I2C_Bus[0]))
In case it is not clear from the other answers already; the correct code organization is:
// stuff.h
//
extern I2C_Bus *const g_I2C_BusPtr_Port0;
extern I2C_Bus *const g_I2C_BusPtr_Port1;
and then:
// stuff.c
//
#include "stuff.h"
I2C_Bus* const g_I2C_BusPtr_Port0 = &g_I2C_Bus[0];
I2C_Bus* const g_I2C_BusPtr_Port1 = &g_I2C_Bus[1];
const ADC123_Device g_Device_ADC123_U14 =
{ { &g_I2C_Bus[0], 0xAE } };
and so on.
Intializers for a static object must either be a constant expression or a string literal, if for example ADC123_Device g_Device_ADC123_U14 was a automatic variable then there would be no error, for example if you declared it in main. We can see this by going to the draft C99 standard section 6.7.8 Initialization which says:
All the expressions in an initializer for an object that has static storage duration shall be
constant expressions or string literals.
The reason why the second case works is that constant addresses are allowed, we can see this from 6.6 Constant expressions which says:
More latitude is permitted for constant expressions in initializers. Such a constant
expression shall be, or evaluate to, one of the following:
and includes the following bullet:
an address constant, or
I'm trying to wrap my head around the syntax provided in http://publib.boulder.ibm.com/infocenter/lnxpcomp/v7v91/index.jsp?topic=%2Fcom.ibm.vacpp7l.doc%2Flanguage%2Fref%2Fclrc03strin.htm :
struct
{
int a[5], b;
} game[] =
{
[0].a = { 1 },
[1].a[0] = 2
};
Ideally, I'd find some way to do the following:
struct
{
int a, b;
} foo =
{
.a = 4,
.b = 5
};
My reason for wanting to have a by-name initialization of a structure is that my own stucture has many members, so I want better clarity. I shouldn't just initialize them in separate statements because this is a performance-sensitive embedded application where the members are actually bitfields, so a single struct init generates fewer instructions than multiple member initializations.
Which C standard allows for by-name member init like that?
It's not immediately clear what you're asking, but with a c99 compiler, your first attempt could be written as
struct
{
int a[5], b;
} game[] =
{
[0] = {.a = { 1 }},
[1] = {.a[0] = 2}
};
I'm doing something similar in an embedded app under C99. I have a variable called phaseInstill that is "assigned" to a struct:
phaseInstill = (PhaseVolumeStatus)
{
.complete = false,
.ticksInstilled = 0,
.volumeInstilled = 0,
.volumeRemaining = instillVolume
};
Where PhaseVolumeStatus is defined as:
typedef struct
{
Value volumeRemaining; /*!> ml */
Value volumeInstilled; /*!> ml */
Value ticksInstilled; /*!> ticks */
bool complete;
} PhaseVolumeStatus;
I don't have a bitfield example handy, but I don't recall it working any differently in any other of my uses.