Background
I am working on a modular architecture for embedded devices, where different levels of abstraction must interact with each other. The current approach is to have many functions, variables, and defines the distorted names of the modules to which they belong.
This approach is a bit painful, and I would like to define some common interfaces for the API. The basic idea is to better understand which modules use the same HAL interface.
Sentence
I would like to use OOP-inspired architecture where I use structures as interfaces. All these structures are statically populated.
This solution looks good, but I can spend a lot of memory because the compiler does not know how to chop off the structures and save only what it really needs.
The following example can be built with or without -DDIRECT , and the behavior should be exactly the same.
Example
Source (test.c)
#include <stdlib.h> int do_foo(int a) { return 42 * a; } #ifdef DIRECT int (*foo)(int) = do_foo; int (*bar)(int); int storage; #else struct foo_ts { int (*do_foo)(int); int (*do_bar)(int); int storage; } foo = {.do_foo = do_foo}; #endif int main(char argc) { #ifdef DIRECT return foo(argc); #else return foo.do_foo(argc); #endif }
Makefile
CFLAGS=-O2 -mthumb -mcpu=cortex-m3 -g --specs=nosys.specs CC=arm-none-eabi-gcc upper=$(shell echo $(1) | tr az AZ) EXEC=direct.out with_struct.out all: $(EXEC) %.out:test.c $(CC) $(CFLAGS) -D$(call upper,$(basename $@ )) -o $@ test.c size $@
Output
You may notice that the memory area used with the struct option is larger because the compiler does not allow itself to delete unused elements.
arm-none-eabi-gcc -O2 -mthumb -mcpu=cortex-m3 -g \ --specs=nosys.specs -DDIRECT -o direct.out test.c size direct.out text data bss dec hex filename 992 1092 36 2120 848 direct.out arm-none-eabi-gcc -O2 -mthumb -mcpu=cortex-m3 -g \ --specs=nosys.specs -DWITH_STRUCT -o with_struct.out test.c size with_struct.out text data bss dec hex filename 992 1100 28 2120 848 with_struct.out
Question
In this example, I demonstrate that using structure is useful for readability and modularity, but it can reduce efficiency and increase memory usage.
Is there a way to get the benefits of both solutions? In other words, is there a way to tell the compiler smarter?
OOP?
Following the comments on this, one suggestion is to use C ++ instead. Unfortunately, the same problem would arise because a class with unused members would never be simplified by the compiler. Therefore, I fall into the same trap with both languages.
Another issue raised was the cause of unused members in structures. To solve this issue, we can present a common 3-axis accelerometer used in an application where only one axis is used. The HAL for this accelerometer can have the read_x_acc , read_y_acc and read_z_acc methods, and the read_z_acc application read_x_acc used.
If I declare a class in C ++ or a structure in C, function pointers to unused methods / functions will still consume memory for nothing.