Определение структуры
Я столкнулся со странным кодом
static ROMCONST struct testcase * ROMCONST *patterns[] = {
patternbmk,
NULL
};
Этот код можно найти здесь.
Что это за определение / объявление структуры?
Может ли кто-нибудь на простом английском объяснить, что это значит?
3 ответа
Что касается ROMCONST
:
Что касается понимания этих заявлений, ROMCONST
это просто какой-то макрос шума, используемый вместо const
.
Такие определения распространены во встроенных системах, где иногда требуется нестандартный материал для размещения данных во флэш-памяти. В частности, этим печально известны архитектуры Гарварда, а также 8/16-битные микроконтроллеры, которым могут потребоваться нестандартные*far
указатели. И, наконец, если таблица размещена в EEPROM/ флэш-памяти данных, она может быть обновлена во время выполнения, несмотря на то, что она доступна только для чтения, поэтому мы бы хотели добавитьvolatile
. Все это можно спрятать внутриROMCONST
. Таким образом, теоретически мы могли бы получить что-то беспорядочное и частично нестандартное, например
#define ROMCONST volatile const far PROGMEM
(Где volatile
из eeprom / data flash, const
для любой вспышки, far
для банковской памяти и PROGMEM
что-то, что используется для объявления данных в ПЗУ на микроконтроллерах Гарварда.)
Пока я просто проигнорирую это и заменю на const
.
Чтобы понять const
-квалификаторы остальной части кода, начните с указанных массивов, например patternbmk
.
const struct testcase * const patternbmk[] = {
Разбираем это по отдельности:
struct testcase * patternbmk[]
объявляет массив указателей на структуры.const struct testcase * patternbmk[]
предоставляет этим указателям доступ только для чтения. Указанные данныеconst
и не могут быть изменены с помощью этих указателей.const struct testcase * const patternbmk[]
делает сами указатели доступными только для чтения, что в основном служит для обеспечения того, чтобы таблица была размещена во флэш-памяти, а не в ОЗУ.
Может быть полезно адаптировать стиль кодирования, например *const
, записывая объявление указателя и его квалификатор вместе.
Затем программист хотел объявить массив указателей на эти массивы указателей. (Как вы можете сказать, что это начинает запутаться...) Есть два способа, которые могут быть использованы для точки в массиве указателей, либо указывая на массив с указателем массива или указывая на первый элемент массива с указателем на указатель. Программист выбрал второе.
Элемент массива имеет тип const struct testcase * const
и чтобы указать на такой элемент, мы добавляем дополнительный *
вправо, заканчивая const struct testcase * const *
. Полезно читать подобные беспорядочные объявления справа налево: указатель на константный указатель на константную структуру testcase.
А потом они захотели сделать массив таких указателей на указатели, просто добавив []
к концу: const struct testcase * const *patterns[]
.
Не то, чтобы каждый инициализатор в этом массиве неявно "распадается" на указатель на первый элемент, поэтому инициализатор patternbmk
распадается на &patternmk[0]
который оказывается указателем на const-указатель на const struct testcase, того же типа, что я обсуждал выше.
И наконец static
квалификатор нужен только для ограничения области видимости переменной файлом, в котором она объявлена. NULL в концеpatterns
список инициализаторов - это контрольное значение, обозначающее конец массива.
В ROMCONST
скорее всего, директива компилятора, и это может быть что-то вроде этого: #define ROMCONST const
что заставляет переменную кодировать раздел памяти.
В patterns
это структура массива, в которой хранится другая структура массива patternbmk
который содержит указатели на функции с определением testcase
структура.
static ROMCONST struct testcase * ROMCONST *patterns[] = {
patternbmk,
NULL
};
ROMCONST struct testcase * ROMCONST patternbmk[] = {
#if !TEST_NO_BENCHMARKS
&testbmk1,
&testbmk2,
&testbmk3,
&testbmk4,
&testbmk5,
&testbmk6,
&testbmk7,
&testbmk8,
#if CH_USE_QUEUES
&testbmk9,
#endif
&testbmk10,
#if CH_USE_SEMAPHORES
&testbmk11,
#endif
#if CH_USE_MUTEXES
&testbmk12,
#endif
&testbmk13,
#endif
NULL
};
ROMCONST struct testcase testbmk1 = {
"Benchmark, messages #1",
NULL,
NULL,
bmk1_execute
};
struct testcase {
const char *name; /**< @brief Test case name. */
void (*setup)(void); /**< @brief Test case preparation function. */
void (*teardown)(void); /**< @brief Test case clean up function. */
void (*execute)(void); /**< @brief Test case execution function. */
};