Я хочу определить массив вещей, например обработчики событий. Содержание этот массив полностью известен во время компиляции, но определен среди несколько единиц компиляции, распределенных между несколькими библиотеками, которые довольно развязаны, по крайней мере до последней (статической) ссылки. мне бы хотелось так держать, так что добавление или удаление компиляции будет также автоматически управляет обработчиком событий, не изменяя центральный список обработчиков событий.
Вот пример того, что я хотел бы сделать (но не работает).
central.h:
typedef void (*callback_t)(void);
callback_t callbacks[];
central.c:
#include "central.h"
void do_callbacks(void) {
int i;
for (i = 0; i < sizeof(callbacks) / sizeof(*callbacks); ++i)
callbacks[i]();
}
foo.c:
#include "central.h"
void callback_foo(void) { }
callback_t callbacks[] = {
&callback_foo
};
bar.c:
#include "central.h"
void callback_bar(void) { }
callback_t callbacks[] = {
&callback_bar
};
Что бы я хотел, это получить один массив callbacks
, который содержит
два элемента: &callback_foo
и &callback_bar
. С помощью приведенного выше кода есть
очевидно, две проблемы:
- Массив
callbacks
определяется несколько раз. -
sizeof(callbacks)
не известен при компиляцииcentral.c
.
Мне кажется, что первый момент может быть решен путем объединения линкера
два символа callbacks
вместо того, чтобы бросать ошибку (возможно, через некоторые
атрибут для переменной), но я не уверен, есть ли что-то подобное.
Даже если есть, проблема sizeof также должна быть решена.
Я понимаю, что общим решением этой проблемы является просто запуск функции или конструктора, который "регистрирует" обратный вызов. Однако я вижу только два способа реализовать это:
- Используйте динамическую память (realloc) для массива обратных вызовов.
- Используйте статическую память с фиксированным размером (как обычно, требуемым).
Поскольку я работаю на платформе микроконтроллеров (Arduino) с ограниченной памятью, ни один из этих подходов не обращается ко мне. И учитывая, что все содержание массив известен во время компиляции, я надеюсь на способ дать возможность компилятору также см. это.
Я нашел этот и это решение, но для этого требуется linker script, что невозможно в среде компиляции. Я (особенно не потому, что для этого потребуется явно называть каждое из этих специальных массивов в компоновщике script, поэтому просто с одним linker script дополнение здесь не работает).
Это решение - лучшее, что я нашел до сих пор. Он использует связанный список который заполняется во время выполнения, но использует память, распределенную статически в каждом (например, следующий указатель выделяется с каждым указатель функции). Тем не менее, накладные расходы этих следующих указателей не должны требуется - есть ли лучший подход?
Возможно, наличие динамического решения в сочетании с оптимизацией времени соединения может как-то приводят к статическому распределению?
Также приветствуются предложения по альтернативным подходам, хотя требуются элементы имеют статический список вещей и эффективность памяти.
Далее
- Использование С++ в порядке, я просто использовал код C выше для иллюстрации проблемы, в большинстве случаев код Arduino - это С++.
- Я использую gcc/avr-gcc, и хотя я бы предпочел переносное решение, то только gcc только нормально.
- У меня есть поддержка шаблонов, но не STL.
- В среде Arduino, которую я использую, у меня нет Makefile или другого способа легко запустить какой-то пользовательский код в compiletime, поэтому я ищу что-то, что может быть полностью реализовано в коде.