Да, вы можете создавать динамические массивы во время компиляции (не во время выполнения) (и спасибо Митчелу Хамферису), идея состоит в том, чтобы объявить ваши обратные вызовы в одном и том же разделе следующим образом:
Пример:
Предположим, у вас есть три файла a.c, b.c main.c и i.h
в 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, \
}
в a.c
#include "i.h"
static void f1(void) {
....
}
ADD_FUNC(f1);
в б.с.
#include "i.h"
static void f2(void) {
....
}
ADD_FUNC(f2);
в 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;
}
ВАЖНО
иногда компилятор оптимизирует переменные начала / конца секций, стирает их, поэтому при попытке их использования у вас будет ошибка компоновщика: ошибка LNK2019: неразрешенный внешний символ ...
, чтобы исправить эту проблему, я использую следующее:
Попробуйте напечатать скрипт компоновщика:
gcc -Wl, -verbose
скопируйте текст между двумя:
============================================ ======
в файле (пример lnk.lds ), вы должны увидеть что-то вроде:
/ * Скрипт для -z combreloc: объединять и сортировать разделы перемещений * /
OUTPUT_FORMAT ("elf64-x86-64", "elf64-x86-64", "elf64-x86-64")
........
- ДОБАВЬТЕ свой раздел в файл сценария компоновщика lnk.lds после раздела .data примерно так (мой определенный раздел называется my_array, как в примере):
__start_my_array = .;
.my_array :
{
*(.my_array)
}
__stop_my_array = .;
Скомпилируйте вашу программу с помощью обновленного скрипта компоновщика, например:
gcc -O3 -Xlinker -T "lnk.lds" file.c -o программа
Если вы наберете строки, программа | grep "__start_my_array" вы должны найти его.