Initializing structure by named members - c

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.

Related

C Nested Structs Initialization

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).

How to fill a global array of structures in c

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.

initialize flexible array members at compile time

I'm trying to optimize boot-time and run-time of an embedded application, and to do that, I'd like to initialize some constant flexible array members at compile time. I've found a few posts that say you must use malloc, but theoretically, it should be possible to do this without...
As an example, say I have:
typedef struct _foo_t {
foo_t *next;
int num_bars;
bar_t bars[];
} foo_t __attribute((__packed__));
And I have literally have several million instances of foo_t. I then have a script to generate a header file with all the information. So I might have something like this:
const foo_t foo1 = {.next = &foo2, .num_bars = 2};
const bar_t foo1_bar1 = {...};
const bar_t foo1_bar2 = {...};
foo_t *const first_foo = &foo1;
But, the problem with this is that the compiler spec does not guarantee that &foo1_bar1 is not guaranteed to be at &foo1.bars[0]. I'm wondering if there's any trickery anyone knows to force the fooX_barY members to be placed in the correct locations in memory.
Note that my goals are:
reduce boot time by avoiding unnecessary mallocs
reduce memory thrashing by having the bar's typically in the same cache pages as corresponding foos
reduce memory requirements by not having pointers to bars
If anyone knows of any good tricks to do this, I'd love to hear them
GCC and clang seem to support standard initializers for flexible arrays so if you can restrict yourself to these compilers, you only need to add casts for const removal. The initializer does not have to use designated members, classic intializers work fine at least for clang.
This extension is actually quite consistent with the C syntax for array initializers where the length of the array can be omitted if it can be determined from the initializer.
For compilers that do not support this syntax, here is a trick to achieve what you want:
//----------------
// you can move these to foo.h
typedef int bar_t;
typedef struct foo_t {
struct foo_t *next;
char name[8];
int num_bars;
bar_t bars[];
} foo_t;
extern foo_t * const first_foo;
extern foo_t * const second_foo;
//----------------
// The definitions can be generated automatically into a separate module
// disable warnings cf: https://stackoverflow.com/a/55877109/4593267
#pragma GCC diagnostic ignored "-Wcast-qual"
#pragma clang diagnostic ignored "-Wcast-qual"
// Trick for VLA initialization
#define foo_t(n) struct { foo_t *next; char name[8]; int num_bars; bar_t bars[n]; }
// using a classic structure initializers
static const foo_t(2) foo2 = { 0, "foo2", 2, { 1, 2 }};
static const foo_t(1) foo1 = { (foo_t *)&foo2, "foo1", 1, { 42 }};
foo_t * const first_foo = (foo_t *)&foo1;
// using a compound literal
foo_t * const second_foo = (foo_t *)&(foo_t(3)){ 0, "foo3", 3, { 10, 20, 30 }};
// using gcc / clang flexible array initializer
#pragma clang diagnostic ignored "-Wgnu-flexible-array-initializer"
static foo_t third_foo = { 0, "foo4", 2, { 1, 2 }};
//----------------
// Test framework
#include <stdio.h>
void foo_print(const char *name, foo_t *p) {
printf("%s: {\n", name);
for (; p; p = p->next) {
printf(" { \"%s\", %d, { ", p->name, p->num_bars);
for (int i = 0; i < p->num_bars; i++)
printf("%d, ", p->bars[i]);
printf("}},\n");
}
printf("}\n");
}
int main() {
foo_print("first_foo", first_foo);
foo_print("second_foo", second_foo);
foo_print("third_foo", &third_foo);
return 0;
}
Output:
first_foo: {
{ "foo1", 1, { 42, }},
{ "foo2", 2, { 1, 2, }},
}
second_foo: {
{ "foo3", 3, { 10, 20, 30, }},
}
third_foo: {
{ "foo4", 2, { 1, 2, }},
}
Your attempts using certain ordering of the related variables is prone to error as the compiler does not need to allocate the variables at the place you want.
The only way to use static variables instead of dynamically allocated memory is to add the members of that flexible array directly into the initializer of your variable:
const foo_t foo1 =
{
.next = &foo2,
.num_bars = 2,
.bars =
{ [0] = {...},
[1] = {...}
}
};
Dedicated initializers are optional.
At least for GCC this should work.
Unfortunately it is not possible to use the common (sizeof(arr)/sizeof(arr[0])) trick to get the number of elements in an array:
foo_t foo1 =
{
.next = &foo2,
.bars =
{ [0] = 1,
[1] = 2
},
.num_bars = sizeof(foo1.bars)/sizeof(foo1.bars[0]),
};
test.c:21:21: error: invalid application of ‘sizeof’ to incomplete type ‘bar_t[]’ {aka ‘int[]’}
21 | .num_bars = sizeof(foo1.bars)/sizeof(foo1.bars[0]),
| ^

Static array initialization in C

Consider the following statements
typedef struct {
int member1;
int member2;
}Custom_t;
void ISR(void)
{
static Custom_t struct1[SOME_CONSTANT];
......
......
}
How can I initialize all member2 variable to a single value in C programming?
If I iniatilize the structure like the one shown below, then there is chance of somebody changing the "SOME_CONSTANT" in a header file and forgetting to update the list.
Another solution would be to give the structure a global scope for the current file. But the only function which uses the structure is the ISR().
void ISR(void)
{
static Custom_t struct1[SOME_CONSTANT] = {
{0, 3},
{0, 3},
......
......
};
......
......
}
Is there any method to solve this problem in C?
You can use Designated Initializers and do it in this way:
#include <stdio.h>
#define SOME_CONSTANT 30
typedef struct {
int member1;
int member2;
} Custom_t;
int main(void)
{
static Custom_t struct1[SOME_CONSTANT] =
{
[0 ... SOME_CONSTANT - 1].member2 = 30
};
printf("%d\n", struct1[25].member2);
printf("%d\n", struct1[19].member2);
printf("%d\n", struct1[0].member2);
return 0;
}
How about to add hard-coded compiling time checking against SOME_CONSTANT in the .c file (e.g. right before the initializer)?
#if SOME_CONSTANT != <some_hard_code_value>
#error "SOME_CONSTANT is not equal to <some_hard_code_value>"
#endif
The rational of this "hard-code" is whenever the SOME_CONSTANT is changed, the initializer need be updated, as well as the compiling time checking.
You don't need to specify the array size in advance, you can compute it later:
static Custom_t struct1[] = {
{0, 3},
{0, 3},
{13,3},
};
#define SOME_CONSTANT (sizeof struct1 /sizeof struct1[0])
or: use __LINE__ to compute the number of elements.
I've had to do something like this with projects with a configurable number of sensors :
[custom_t.h]
typedef struct {
int member1;
int member2;
}Custom_t;
#define MAX_CUSTOM_T 4
Custom_t *new_Custom_t (int member1, int member2);
[custom_t.c]
#include "custom_t.h"
static Custom_t g_Customt[MAX_CUSTOM_T];
static uint8 g_numCustom_t = 0;
Custom_t *new_Custom_t (int member1, int member2)
{
if ( g_numCustom_t < MAX_CUSTOM_T )
{
Custom_t *new_obj = &g_Customt[g_numCustom_t++];
new_obj->member1 = member1;
new_obj->member1 = member2;
return new_obj;
}
else
{
// throw exception?
// or go into while(1)?
// or software breakpoint if debug?
// or just...
return NULL;
}
}
[main.c]
#include "custom_t.h"
Custom_t *myCustom1;
Custom_t *myCustom2;
Custom_t *myCustom3;
somefunc()
{
myCustom1 = new_Custom_t (0,3);
myCustom2 = new_Custom_t (1,3);
myCustom3 = new_Custom_t (2,3);
// do stuff
}
It means if you want to create a new one, you may or may not need to update MAX_CUSTOM_T depending on its size already, but will just have to add a new line call to new_Custom_t(int,int). A Disadvantage though is it is slightly complex for what you might need, and if you ever want to add more members to initialize, you'll need to update the parameters passed into the new_ function to suit. This can be done instead with a sending a single separate structure for parameters rather than multiple parameters (a bit like MPLAB harmony).

Unclear structure variable usage - C

While browsing through the Linux kernel code, I came across something like this.
struct dma_chan {
int lock;
const char *device_id;
};
static struct dma_chan dma_chan_busy[MAX_DMA_CHANNELS] = {
[4] = { 1, "cascade" },
};
what is this - [4] = { 1, "cascade" }, - usage implying ?
Note : Kernel version is 2.6.32
This is a designated initializer. It initializes the fifth element to { 1, "cascade" } explicitly, the other ones are default-initialized.

Resources