У меня есть заголовочный файл C (.h):
typedef uint8_t paraFunction(uint8_t paraVal, uint8_t paraNum);
paraFunction *paraCallTable[256];
И у меня есть исходный файл C (.c):
paraFunction *paraCallTable[] = { fn1, fn2, ... fn255, fn256 };
Однако массив оказывается в разделе данных. Я хочу, чтобы это было в коде/флэш-памяти, потому что адреса функций (данные массива) постоянны. Массив используется функциями в других исходных файлах.
Как мне переписать эти объявления, чтобы сделать их постоянными? И где они должны быть (.c или .h)?
Я погуглил и попробовал массу разных способов, но, очевидно, просто не понял.
@dbush Потому что у меня есть только 24 КБ SRAM для работы (процессор — STM32F373CB). И мне нужно получить константы из SRAM, чтобы все переменные поместились в SRAM.
paraFunction *const paraCallTable[]
?
Сделать его постоянным не обязательно будет достаточно, чтобы разместить его во флэш-памяти. Это зависит от платформы и цепочки инструментов. Возможно, вам придется войти в настройки компоновщика и, возможно, в небольшой файл сборки.
@AviBerger Возможно, но это, вероятно, первый шаг.
@Бармар, Согласен.
Думаю, я мог бы определить новый раздел (ConstArray) в файле компоновщика, который помещает массив во флэш-память (после использования чего-то вроде __attribute__((section(".ConstantArray"))) в объявлении массива). Я сделал это при объявлении функций, которые должны попасть в SRAM. Но я бы подумал, что определение массива как константы автоматически поместило бы его в раздел flash/code. В противном случае, какой смысл в глаголе «const» применительно к переменным?
Обычно он помещает его в текстовый раздел, аналогично коду. Если ваш компилятор помещает код во флэш-память, он, вероятно, будет делать то, что вы хотите.
@Barmar — paraFunction *const paraCallTable[] работает отлично! Клянусь, я пробовал это. Я чувствую себя полным идиотом.
@Катумба, может, ты пробовал paraFunction const *paraCallTable[]
или const paraFunction *paraCallTable[]
? Его семантика отличается от paraFunction *const paraCallTable[]
.
@freestyle Я уверен, что ты прав. В любом случае, моя проблема вполне решена. Теперь мне нужно прочитать еще немного, чтобы (заново) изучить семантику.
@Katoomba: Правило простое. Если вы пишете const
перед *
, вы указываете, что объект, на который указывает указатель, — это const
. Если вместо этого вы напишете const
после *
, вы укажете, что сам указатель равен const
.
Поскольку вы уже используете самую ясную (ИМХО) форму указателя функции typedef
, это просто вопрос добавления const
к объявлению в правой части *
, как вы бы это сделали с указателем объекта, который вы хотели бы разместить в ПЗУ. :
paraFunction *const paraCallTable[]
Если бы вы использовали форму typedef uint8_t (*paraFunction)(uint8_t paraVal, uint8_t paraNum);
, вам пришлось бы использовать гораздо менее очевидную и запутанную форму const paraFunction paraCallTable[]
. Это указатель на данные, доступные только для чтения, а не данные, доступные только для чтения, или указатель на данные, доступные только для чтения, как можно было бы подумать.
Это веский аргумент в пользу того, чтобы придерживаться хорошего typedef
стиля, который вы уже используете.
Мы также можем отметить, что хорошей практикой является всегда объявлять таблицы указателей функций как * const
, ROM или без ROM, поскольку изменение указателей функций во время выполнения чаще всего нежелательно.
Спасибо за краткое и дополнительное объяснение.
«массив попадает в раздел данных». Почему это имеет значение?