Typedef для постоянного указателя на массив функций постоянных данных

У меня есть заголовочный файл 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 28.06.2024 02:11

@dbush Потому что у меня есть только 24 КБ SRAM для работы (процессор — STM32F373CB). И мне нужно получить константы из SRAM, чтобы все переменные поместились в SRAM.

Katoomba 28.06.2024 02:14
paraFunction *const paraCallTable[]?
Barmar 28.06.2024 02:17

Сделать его постоянным не обязательно будет достаточно, чтобы разместить его во флэш-памяти. Это зависит от платформы и цепочки инструментов. Возможно, вам придется войти в настройки компоновщика и, возможно, в небольшой файл сборки.

Avi Berger 28.06.2024 02:17

@AviBerger Возможно, но это, вероятно, первый шаг.

Barmar 28.06.2024 02:18

@Бармар, Согласен.

Avi Berger 28.06.2024 02:26

Думаю, я мог бы определить новый раздел (ConstArray) в файле компоновщика, который помещает массив во флэш-память (после использования чего-то вроде __attribute__((section(".ConstantArray"))) в объявлении массива). Я сделал это при объявлении функций, которые должны попасть в SRAM. Но я бы подумал, что определение массива как константы автоматически поместило бы его в раздел flash/code. В противном случае, какой смысл в глаголе «const» применительно к переменным?

Katoomba 28.06.2024 02:27

Обычно он помещает его в текстовый раздел, аналогично коду. Если ваш компилятор помещает код во флэш-память, он, вероятно, будет делать то, что вы хотите.

Barmar 28.06.2024 02:29

@Barmar — paraFunction *const paraCallTable[] работает отлично! Клянусь, я пробовал это. Я чувствую себя полным идиотом.

Katoomba 28.06.2024 02:31

@Катумба, может, ты пробовал paraFunction const *paraCallTable[] или const paraFunction *paraCallTable[]? Его семантика отличается от paraFunction *const paraCallTable[].

freestyle 28.06.2024 02:57

@freestyle Я уверен, что ты прав. В любом случае, моя проблема вполне решена. Теперь мне нужно прочитать еще немного, чтобы (заново) изучить семантику.

Katoomba 28.06.2024 04:34

@Katoomba: Правило простое. Если вы пишете const перед *, вы указываете, что объект, на который указывает указатель, — это const. Если вместо этого вы напишете const после *, вы укажете, что сам указатель равен const.

Andreas Wenzel 28.06.2024 13:39
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
4
12
72
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Поскольку вы уже используете самую ясную (ИМХО) форму указателя функции typedef, это просто вопрос добавления const к объявлению в правой части *, как вы бы это сделали с указателем объекта, который вы хотели бы разместить в ПЗУ. :

paraFunction *const paraCallTable[]

Если бы вы использовали форму typedef uint8_t (*paraFunction)(uint8_t paraVal, uint8_t paraNum);, вам пришлось бы использовать гораздо менее очевидную и запутанную форму const paraFunction paraCallTable[]. Это указатель на данные, доступные только для чтения, а не данные, доступные только для чтения, или указатель на данные, доступные только для чтения, как можно было бы подумать.

Это веский аргумент в пользу того, чтобы придерживаться хорошего typedef стиля, который вы уже используете.

Мы также можем отметить, что хорошей практикой является всегда объявлять таблицы указателей функций как * const, ROM или без ROM, поскольку изменение указателей функций во время выполнения чаще всего нежелательно.

Спасибо за краткое и дополнительное объяснение.

Katoomba 28.06.2024 12:16

Другие вопросы по теме