I have defined the two-dimensional array inside the typedef struct as,
#define MAX_STAGES_IIR 20
typedef struct {
float A[MAX_STAGES_IIR]; // Input Gain
float a[MAX_STAGES_IIR][2]; // input stage coff
float b[MAX_STAGES_IIR][3]; // output stage coff
// float B[MAX_STAGES_IIR]; // output gain
float Xdash[MAX_STAGES_IIR][2];
float iir_k[MAX_STAGES_IIR];//
float iir_r[MAX_STAGES_IIR];//
float iir_outStage[MAX_STAGES_IIR];
}IIRFilter;
When assigning values to the array use this method,
IIRFilter BpfHX_iir1;
BpfHX_iir1.A = { 0.131726 , 0.131726 , 0.12435, 1.0f }; // gain
BpfHX_iir1.a = {{-1.63410, 0.82662},{-1.87089, 0.91410},{-1.6652, 0.7513}}; // a
BpfHX_iir1.b = {{1, 0, -1},{1, 0, -1},{1, 0, -1}}; // b
but the Mplab XC16 can't build this method.
gives the same error message for all three arrays,
expected expression before '{' token
expected expression before '{' token
expected expression before '{' token
what is the reason for that?
is there a correct method to do that in XC16?
Initialize BpfHX_iir1 in the usual way.
Use float constants and not double ones for the float array. (Append an f.)
IIRFilter BpfHX_iir1 = { //
.A = {0.131726f, 0.131726f, 0.12435f, 1.0f}, //
.a = { {-1.63410f, 0.82662f}, {-1.87089f, 0.91410f}, {-1.6652f, 0.7513f}}, //
.b = { {1, 0, -1}, {1, 0, -1}, {1, 0, -1}} //
};
All members of BpfHX_iir1 will be initialized. Those not explicitly coded above will have a zero bit-pattern.
To assign an array *1 via memcpy() at a later time is easy if the compiler is C99 compliant. Use a compound literal.
void foobar(void) {
IIRFilter BpfHX_iir1;
// v-------------------------------- compound literal ---------v
memcpy(BpfHX_iir1.A, (float[MAX_STAGES_IIR]){0.131726f, 0.131726f, 0.12435f, 1.0f}, sizeof BpfHX_iir1.A);
...
}
Or the old fashion way:
const float A0[MAX_STAGES_IIR] = {0.131726f, 0.131726f, 0.12435f, 1.0f};
memcpy(BpfHX_iir1.A, A0, sizeof BpfHX_iir1.A);
*1 Arrays cannot be simply assigned in C. They can be copied via memcpy(), just like any object.
struct mystruct s[10] = {{0}};
This appears to initialize an array of structs to 0. How does the nested braces syntax work?
Any fields not specified are initialized to zero. So here you have an array of structs. You're initializing the first element of the array with a structure initializer that initializes the first element of the structure to zero. The rest of the first structure and the rest of the array elements will all be zero too. It's a nice idiom.
As shown?
Basically, you should enclose each compound type - array, structure, etc - inside its own level of braces.
Consider:
struct mystruct
{
int i;
double d;
char s[10];
int a[5];
} s[10] =
{
{ 0, 0.0, "abc", { 1, 2, 3, 4, 5 } },
{ 1, 1.0, "def", { 2, 3 } }, // Partially initialized array
{ 2, 2.0, { 'x', 'y', 'z' }, { 0 } }, // Strings are a shorthand
[9] = { 9, 99, 0, { 9, 8, 7, 6, 5 } }, // C99 - initialize row 9
};
But you can also omit braces if you insist (bad, archaic practice):
struct mystruct t[3] =
{ // You cannot avoid using these outside braces
0, 0.00, "abc", 1, 2, 3, 4, 5, // Omitted braces
1, 1.11, "bcd", 2, 3, 4, 5, 4,
2, 2.34, // Omitted values
};
Any omitted initializers are treated as zeroes.
It is not the nested braces that initializes. The outer braces are indicating that an array is being initialized:
struct mystruct s[10] = { };
Since this is an array of structures, each structures can be initialized with further braces:
struct mystruct { int x, y, z};
struct mystruct s[10] = { {0, 1, 2}, // <-- initializes s[0].x, s[0].y, s[0].z
{1, 2, 3}, // <-- initializes s[1].x, s[1].y, s[1].z
{2, 3, 4} // <-- initializes s[2].x, s[2].y, s[2].z
};
Notice that only first three elements are initialized. According to C standard the rest 7 elements must be initialized to 0. This is what happens to your code too. As xscott mentioned in his reply, everything omitted in initializer list is initialized to 0.
It's useful to note that while the inner braces are optional, the compiler will check to ensure that opening braces only appear where they ought, and that no nested item has too many initializers. Further, one may leave out some fields of a structure and have the compiler automatically zero them, even if the structure is not at the end of the array. Note that implementations vary in their efficiency of handling this; some will divide the initialization record into small pieces, while others will simply insert lots of zeroes in the code. For example, if each struct looked like:
typedef struct {
char name[8];
char more_stuff[1016];
} THINGIE;
THINGIE my_array[] = {{"Fred"},{"George"},{"Mark"}};
some compilers would generate 3K worth of const data, while others would generate three relatively-small 'const-init' records.
I'm re-writing a function (it works, so I'm apparently eager to break it) that iterates through an 2-D array. The function will read an INI file for the contents of a given key, and either store the value returned to a variable or store a default value to the variable (in my structure, the variable is defined by reference as *pStoreToRef).
Support for storing a default value in my 2-D array is proving difficult. All data types must be accommodated. How to do so?
The 2-D array is typed by a structure:
typedef struct s_defaults {
char *cKeyTitle;
uint16_t nItemNr;
uint8_t nVarType;
int *pDefaultValue;
uint16_t nVarLength;
uint8_t nVarFloatDecimals;
char *pFormatString;
int *pStoreToRef;
int nNextItem; // set to -1 at end
} site_defaults_t;
Here's the initializer:
site_defaults_t site_defaults[] =
{
{"AUTOTUN_TOTAL_CYCLES\0", SD_AUTORUN_TOTAL_CYCLES, VT_INTEGER, 192, 5, 0, "%i\0", (int*)&aAutoRunControl.nTotalCycles,1},
{"AUTORUN_TEST_INTERVAL\0", SD_AUTORUN_TEST_INTERVAL, VT_INTEGER, 60, 5, 0, "%i\0", (int*)&aAutoRunControl.nTestIntervalSecs,2},
{"AUTORUN_TEST_LEN_SECS\0", SD_AUTORUN_TEST_LEN_SECS, VT_INTEGER, 30, 6, 0, "%i\0", (int*)&aAutoRunControl.nTestLengthSecs,3},
{"AUTORUN_TEST_FAN_SPEED\0", SD_AUTORUN_TEST_FAN_SPEED, VT_INTEGER, 85, 3, 0, "%i\0", (int*)&aAutoRunControl.nSpeed,4},
{"AUTORUN_TEST_PLATE_VOLTS\0", SD_AUTORUN_TEST_PLATE_VOLTS, VT_FLOAT, 40, 3, 1, "%2.1f\0", (int*)&aAutoRunControl.vPlate,5},
{"AUTORUN_TEST_SAMPLES_PER_SEC\0", SD_AUTORUN_TEST_SAMPLES_PER_SEC, VT_INTEGER, 10, 2, 0, "%i\0", (int*)&aAutoRunControl.nSamplesPerSecond,6},
{"SEND_FILES_FREQUENCY\0", SD_SEND_FILES_FREQUENCY, VT_INTEGER, 10, 6, 0, "%i\0", (int*)&oSystemInfo.nSendFilesFrequency,7},
{"POWER_60_HZ\0", SD_POWER_60_HZ, VT_BOOLEAN, true, 1, 0, "%i\0", (int*)&aSystemState.Power60Hz,8},
{"UPLOAD_ON_BOOT\0", SD_UPLOAD_ON_BOOT, VT_BOOLEAN, false, 1, 0, "%i\0", (int*)&oSystemInfo.EnableSendFilesOnBoot,9},
{"AUTORUN_SENDFILES\0", SD_AUTORUN_SENDFILES, VT_BOOLEAN, true, 1, 0, "%i\0", (int*)&aAutoRunControl.sendFiles,10},
{"PREAMP_TRIM\0", SD_PREAMP_TRIM, VT_FLOAT, 0, 3, 1, "%2.1f\0", (int*)&aSystemState.nPreampTrim,11},
{"AUTORUN_PCIL_CONVERSION_CONST\0", SD_AUTORUN_PCIL_CONVERSION_CONST, VT_FLOAT, 0.07608, 2, 8, "%2.8f\0", (int*)&aAutoRunControl.pcilMult,12},
{"ENABLE_DVDT_BEEP\0", SD_ENABLE_DVDT_BEEP, VT_BOOLEAN, false, 1, 0, "%i\0", (int*)&oSystemInfo.AllowDvDtBeep,13},
{"AUTORUN_PCIL_CONVERSION_ADJUST\0",SD_AUTORUN_PCIL_CONVERSION_ADJUST, VT_FLOAT, 0.02, 2, 8, "%2.8f\0", (int*)&aAutoRunControl.pcilMultAdjust,14},
{"AUTORUN_DEMO_DURATION\0", SD_AUTORUN_DEMO_DURATION, VT_INTEGER, 30, 5, 0, "%i\0", (int*)&aAutoRunControl.nDemoDuration,-1},
};
The new field, int *pDefaultValue; is proving problematic. My theory was to store a reference to the value, and in this manner the stored pDefaultValue can be any type. That should work if the default value to store could be referenced to an address, but in this case?
Any ideas as to a work-around?
I believe your best choice is to have two members in this structure instead of just pDefaultValue. The first one is the string form of the default value, say, pDefaultValueStr. The other is pDefaultValue, which should be declared void * and to which the default value is stored in its internal form: the one that would be cast when the getter function needs to get one.
You would then execute an initializer population function early in the program execution that populates pDefaultValue given the content of pDefaultValueStr and switch upon nVarType.
The initializer, site_defaults, would have a null pointer given to each element's pDefaultValue and would be replaced by a usable, freeable, value by the initializer population function or it would "die" if the value cannot be converted from a string to its internal representation.
This initializer population function has utility also if the site defaults have to change given some input (string of course) from a user.
The simplest and not so great approach is to union it:
typedef struct s_defaults {
uint8_t nVarType;
union some_union_name_in_case_you_dont_have_c11 {
float f;
int i;
bool b;
} pDefaultValue;
};
struct s_defaults site_defaults[] = {
{ VT_INTEGER, { .i = 192 }, },
{ VT_FLOAT, { .f = 1.92 }, },
{ VT_BOOL, { .b = true }, },
};
This results in many pages long switch-like statements to handle each type.
A way better way would be to use a function pointers and proper interface overloading.
struct s_default_vtable {
void (*assign)(void *to, const void *value, void *cookie);
void (*print)(const void *value, const char *fmt, void *cookie);
};
void assign_float(void *to, const void *value, void *cookie) {
*(float*)to = *(const float*)value;
}
void print_float(const void *value, const char *fmt, void *cookie) {
printf(fmt, *(const float*)value);
}
const struct s_default_vtable s_default_vtable_float = {
.assign = assign_float,
.print = print_float,
};
// similar for int and bool types
typedef struct s_defaults {
const struct s_default_vtable *v; // vtable pointer
void *cookie; // user context to pass to vtable functions
const void *pDefaultValue;
const char *pFormatString; // as this is tied to the type,
// I think it should be moved into vtable
// or just hardcoded into print function
void *pStoreToRef;
} site_defaults_t;
Note that you can still use pages long switch statements by comparing the vtable pointer. Then you can use for example like:
// example for float type
float number_to_store_result_to;
const float float_default_value = 50.0;
struct s_defaults defaults = {
.v = &s_default_vtable_float ,
.cookie = 0,
.default_value = &float_default_value.
.pFormatString = "%f",
.pStoreToRef = &number,
};
// assign default value to pStoreToReg
// no need for switch, no need for anything
defaults.v->assign(defaults.pStoreToReg, defaults.default_value, defaults.cookie);
Notes:
String literals include zero terminating character. There is no need for \0" (unless you really mean to have two zero characters on the end of the string).
The members:
uint16_t nVarLength;
uint8_t nVarFloatDecimals;
char *pFormatString;
rigth now duplicate information in your structure. You need only the format specifier for the type, for example for float you need f. The %<this>.<this> can be build dynamically with a small static buffer.
void print_float(int nVarLength, int nVarFloatDecimals, const char *pFormatString, float *value) {
char buf[100];
snprintf(buf, sizeof(buf), "%%%d.%d%s", nVarLength, nVarFloatDecimals, pFormatString);
printf(buf, *(float*)value);
}
// call like:
print_float(2, 8, "f", 1.0);
Here's one of many possible solutions. Since you're using VARIANTs to describe information, let's use VARIANT.
I've trimmed away other struct members for clarity since this is all about initializing the VARIANT and in this case irrelevant.
First an augmented struct for this example:
typedef struct SiteMeta {
char* name;
VARIANT v;
};
Define a function to initialize a VARIANT.
VARIANT VariantValInit(const VARTYPE vt, const void* value) {
VARIANT v;
VariantInit(&v);
v.vt = vt;
switch (vt) {
case VT_I4:
v.intVal = (int)value;
break;
case VT_BOOL:
v.boolVal = (bool)value;
break;
default:
// throw or something.
break;
}
return v;
}
Of course the function above would require additional cases to support other types.
Now declare your defaults like so:
SiteMeta site_defaults[] =
{
{ "AUTOTUN_TOTAL_CYCLES", VariantValInit(VT_I4, (void*)192) },
{"POWER_60_HZ", VariantValInit(VT_BOOL, (void*)true) }
};
String literals such as "AUTOTUN_TOTAL_CYCLES" implicitly include a null terminator. So "AUTOTUN_TOTAL_CYCLES\0" is actually placing two NULL terminators, one implicit, the other explicit. It's not necessary.
Additionally, because you are initializing the struct with an initializer, the type of the first member could be modified to: const char *cKeyTitle;
Next, The code as is produces an error message to the effect of "unexpected type name "VT_INTEGER" (and similar for other type names) for the struct initializer site_defaults_t site_defaults[]
This is because a C type cannot be used as a value. This would be similar to doing this:
struct {
int int;
float float;
...
Following is a reduced scale replica of your original code for the purpose of showing how you might be able to solve your problem replacing void * for creating a flexible type to using a union:
This is a bare bones example, but includes a main function just so you can build it and experiment to see how the union works...
typedef enum {
SD_AUTORUN_TOTAL_CYCLES,
SD_AUTORUN_TEST_INTERVAL,
SD_AUTORUN_TEST_LEN_SECS,
SD_AUTORUN_TEST_FAN_SPEED,
SD_AUTORUN_TEST_PLATE_VOLTS,
SD_AUTORUN_TEST_SAMPLES_PER_SEC,
SD_MAX //count of items in enum list
}TASK;
typedef enum {
V_INTEGER,//replace VT_INTEGER in initializer
V_FLOAT,
V_BOOLEAN,
}TYPES;
typedef union {
int iVar;
float fVar;
bool bVar
}U_TYPE;
typedef struct s_defaults {
char *cKeyTitle;
uint16_t nItemNr;
uint8_t nVarType;
U_TYPE uVar;//union of types
} site_defaults_t;
site_defaults_t site_defaults[] =
{
{"AUTOTUN_TOTAL_CYCLES", SD_AUTORUN_TOTAL_CYCLES, V_INTEGER, 2},
{"AUTORUN_TEST_INTERVAL", SD_AUTORUN_TEST_INTERVAL, V_INTEGER, 8},
{"AUTORUN_TEST_LEN_SECS", SD_AUTORUN_TEST_LEN_SECS, V_INTEGER, 20},
{"AUTORUN_TEST_FAN_SPEED", SD_AUTORUN_TEST_FAN_SPEED, V_INTEGER, 0},
{"AUTORUN_TEST_PLATE_VOLTS", SD_AUTORUN_TEST_PLATE_VOLTS, V_FLOAT, 123.56},
{"AUTORUN_TEST_SAMPLES_PER_SEC", SD_AUTORUN_TEST_SAMPLES_PER_SEC, V_INTEGER, 15}
};
int main(void)
{
return 0;
}
I have a struct with a single member. This member is actually a pointer to pointer to integer, in order to represent a 2-dimensional integer array.
Can I use scalar initialization while creating an instance of that struct?
I am trying to create a 2-dimensional array to represent a collection of pixels for an algorithm exercise.
I should represent something like this:
{
{ 0, 0, 1, 0, 0 },
{ 0, 1, 1, 1, 0 },
{ 1, 1, 1, 1, 1 }
}
In order to represent a generic abstraction of an image, I tried to create a struct with the following structure:
struct image_t
{
unsigned short int** pixels;
};
And so I try to init an instance of that by using:
int
main()
{
struct image_t image = {
{
{0, 0, 1, 0, 0},
{0, 1, 1, 1, 0},
{1, 1, 1, 1, 1},
}
};
return 0;
}
When I try to compile, the following warnings are given:
gcc -I src src/main.c -o bin/flood-fill.bin
src/main.c: In function ‘main’:
src/main.c:41:5: warning: braces around scalar initializer
{
^
src/main.c:41:5: note: (near initialization for ‘image.pixels’)
src/main.c:42:7: warning: braces around scalar initializer
{0, 1, 0},
^
src/main.c:42:7: note: (near initialization for ‘image.pixels’)
src/main.c:42:11: warning: excess elements in scalar initializer
{0, 1, 0},
^
src/main.c:42:11: note: (near initialization for ‘image.pixels’)
src/main.c:42:14: warning: excess elements in scalar initializer
{0, 1, 0},
After making some research, I realized that, as it is gonna be an image representation, each row will have the same total of columns. Due that, I can just use a single array and store everything in a single block of memory. It resolves my problem.
However, as a curious guy, I would like to know if there is any way to use scalar initialization for such cases - if so, how can I do that?
Most likely I'm missing some critical basic concept from C language, so explanations are more than welcome. I really want to understand better the way it works under the hood.
It probably isn't a good idea, but you can use compound literals to create the structure you want, like this:
struct image_t
{
unsigned short int **pixels;
};
int main(void)
{
struct image_t image =
{
(unsigned short *[]) {
(unsigned short []){ 0, 0, 1, 0, 0 },
(unsigned short []){ 0, 1, 1, 1, 0 },
(unsigned short []){ 1, 1, 1, 1, 1 },
}
};
return image.pixels[1][4];
}
Note that one of the problems with the data structure shown is that there is no information about how many rows are in the array of pointers, nor how many items are in each row (and there's no guarantee that each row is the same length as the other rows). That alone is reason enough to think that the structure is broken (badly designed, at any rate). If you added information about the rows and columns, then it could be OK.
Note that unsigned short **pixels; is not a pointer to a 2D array. It is a pointer to (an array of) pointer(s), which is quite different.