I have an array (C language) that should be initialized at compile time.
For example:
DECLARE_CMD(f1, arg);
DECLARE_CMD(f2, arg);
The DECLARE_CMD is called from multiple files.
I want this to be preprocessed in.
my_func_type my_funcs [] = {
&f1,
&f2
}
It is possible, with a macro, to append items to an static array?
I am using C99 (with GNU extensions) on gcc4.
An array is a contiguous block of memory and if you want to append an element, you have to write it to the position following the last occupied position, provided the array is large enough.
In C programming language we can also use Macro to define a constant. As we know that, while declaring an array we need to pass maximum number of elements, for example, if you want to declare an array for 10 elements. You need to pass 10 while declaring. Example: int arr[10];
Yes, you can build dynamic arrays at compile time (not at runtime) (and thank's to Mitchel Humpherys), the idea is to declare your callbacks in the same section like this:
EXAMPLE:
Suppose you have three files a.c, b.c main.c and i.h
into i.h
typedef void (*my_func_cb)(void);
typedef struct func_ptr_s {
my_func_cb cb; /* function callback */
} func_ptr_t;
#define ADD_FUNC(func_cb) \
static func_ptr_t ptr_##func_cb \
__attribute((used, section("my_array"))) = { \
.cb = func_cb, \
}
into a.c
#include "i.h"
static void f1(void) {
....
}
ADD_FUNC(f1);
into b.c
#include "i.h"
static void f2(void) {
....
}
ADD_FUNC(f2);
into main.c
#include "i.h"
static void f3(void) {
....
}
ADD_FUNC(f3);
#define section_foreach_entry(section_name, type_t, elem) \
for (type_t *elem = \
({ \
extern type_t __start_##section_name; \
&__start_##section_name; \
}); \
elem != \
({ \
extern type_t __stop_##section_name; \
&__stop_##section_name; \
}); \
++elem)
int main(int argc, char *argv[])
{
section_foreach_entry(my_array, func_ptr_t, entry) {
entry->cb(); /* this will call f1, f2 and f3 */
}
return 0;
}
IMPORTANT
sometimes the compiler optimizes start/end sections variables, it wipes them out, so when you try to use them, you will have a linker error: error LNK2019: unresolved external symbol ...
to fix this problem, i use the following:
Try to print your linker script:
gcc -Wl,-verbose
copy the text between the two:
==================================================
in a file (example lnk.lds), you should see thing like:
/* Script for -z combreloc: combine and sort reloc sections */
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64","elf64-x86-64")
........
__start_my_array = .;
.my_array :
{
*(.my_array)
}
__stop_my_array = .;
Compile your program with the updated linker script like this:
gcc -O3 -Xlinker -T"lnk.lds" file.c -o program
If you type strings program | grep "__start_my_array" you should find it.
NOTE: in your question there are semicolons at the end of every line. This will seriously interfere with any attempt to use these macros. So it depends on where and how the DECLARE_CMD(...)
lines are found, and whether you can fix the semicolon problem. If they are simply in a dedicated header file all by themselves, you can do:
#define DECLARE_CMD(func, arg) &func,
my_func_type my_funcs [] {
#include "file_with_declare_cmd.h"
};
...which gets turned into:
my_func_type my_funcs [] {
&f1,
&f2,
};
Read The New C: X Macros for a good explanation of this.
If you can't get rid of the semicolons, this will be processed to:
my_func_type my_funcs [] {
&f1,;
&f2,;
};
... which is obviously a syntax error, and so this won't work.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With