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]),
| ^
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).
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
}
},
};
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).
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.
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.