2016-11-15 6 views
1

Может кто-нибудь сказать, что означает этот код?В чем смысл этой части кода?

void (* const rvt[])(void) = { 
    (void (*) (void))((unsigned long)&__STACK_END), // The initial stack pointer 
    xkg_som,         // The reset handler 
    xnt_ISR,         // The NMI handler 
    FaultISR,         // The hard fault handler 
    IntDefaultHandler,      // The MPU fault handler 
    bgs_stm,         // The bus fault handler 
    IntDefaultHandler,      // The usage fault handler 
    0,          // Reserved 
    0,          // Reserved 
    IntDefaultHandler,      // The MPU fault handler 
}; 

Я действительно не понимаю.

+0

пытается передать фактический адрес в тип указателя функции ... использовать его позже ... но я запутался в типах там ... –

+7

Это выглядит как [таблица векторов прерываний] (https://en.wikipedia.org/wiki/Interrupt_vector_table). – user694733

+1

Для справок в будущем вы всегда можете попробовать [cdecl] (http://cdecl.ridiculousfish.com/?q=void+%28*+const+rvt%5B%5D%29%28void%29) для подсказки. – Useless

ответ

8
void (* const rvt[])(void) 

средство (любезно cdecl.org):

объявить RVT, как массив константного указателя на функцию (пустоту) возвращение недействительным


T foo = { 
    value1, 
    value2, 
    value3 // ... 
}; 

Thi s - aggregate initialization [1] массива. Кроме того, это означает, что определение rvt является определением.


&__STACK_END 

Оператор addresof принимает адрес памяти переменной.

(unsigned long)&__STACK_END) 

Адрес отливают в unsigned long типа.

(void (*) (void))((unsigned long)&__STACK_END) 

Преобразованное значение снова отливают на указатель на функцию (пустоты) возвращение пустоты, который является типом указателей функций, хранящихся в массиве.


Остальные инициализируются значения массива могут быть либо имена функций, указатели на функции или что-то, что может быть неявно преобразован в указатель функции, такие как лямбды.

+2

Нет никакой «инициализации списка копий» в C. – Olaf

+0

Это фактически простой список инициализаторов массива. Конструкторы, очевидно, не называются, а также «lambdas», так как это таблица векторов прерываний. Нет ничего, что можно было бы вычислить, и ничего не должно было быть сделано во время выполнения. – Lundin

+0

@ Lundin Чтобы прояснить мой ответ, он не предполагает никакого контекста, поскольку ни один из них не был предоставлен. Я не описываю переменные (поскольку я этого не знаю); Я описываю, что может быть, учитывая только код и никакой контекст. Что касается вашего последнего предложения, нет ли постоянной инициализации в начале времени выполнения (при условии, что таблица является статической)? – user2079303

1

Он определяет массив указателей на функции, которые принимают не принимать аргументы и возвращать пустоту. Затем массив инициализируется адресами некоторых регистров в памяти, которые передаются в указатели функций.

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

+0

Массив, скорее всего, является векторной таблицей, но он инициализируется из констант и функций компиляции, а не из регистров в памяти. Инициализация из регистров невозможна, поскольку массив доступен только для чтения. – Lundin

3
void (* const rvt[])(void) 

Это определяет массив констант с именем «rvt». Его элементы являются указателями на функцию void без аргументов.

Этот массив затем инициализируется списком инициализации скобок. Таким образом, все остальные строки являются элементами этого массива. Первый - это указатель на __STACK_END, который, по-видимому, имеет неправильный тип и, следовательно, должен быть переведен в правильный тип (сначала он будет вызываться в unsigned long, а затем в правый указатель функционального типа).

Btw: код неполный, так как скобка не закрыта, или, может быть, ваше форматирование пошло не так, поскольку последний комментарий содержит заключительную фигуру?

+0

'Это определяет массив констант с именем« rvt ». Итак,' Array' здесь 'const' и не является' const pointer'? – Michi

+0

@Michi: Да. Сами функции неявно неявно (вы не можете применять 'const' к самой функции). Я бы стал более понятным, используя 'typedef' для функции (указатель). – Olaf

+0

@Olaf Это была моя точка зрения. Но почему этот ответ делает его другим? – Michi

0

Это, как представляется, таблица векторов прерываний для микроконтроллера ARM Cortex M.

enter image description here

одна особенности в ARM Cortex по сравнению с большинством других микроконтроллеров, является то, что он имеет указатель стека, поставленный перед началом программы. Другие MCU, как правило, устанавливают его во время выполнения.

Таким образом, самая первая запись в таблице - это значение, которое должен указывать указатель стека при запуске программы. __STACK_END, вероятно, является константой, полученной из компоновщика. Листинг (void (*) (void)) превращает его в указатель функции. Кастинг от указателя на int до указателя функции немного сомнителен, но, скорее всего, он будет работать на большинстве встроенных компиляторов C, несмотря на то, что C-стандарт нахмурился.

Остальные записи являются функциональными адресами для прерывания сервисных процедур (функций). То есть, это то же самое, что и указатели на функции. Вы можете инициализировать указатель функции, указав ей имя функции.

Вся векторная таблица поэтому объявлена ​​как массив указателей на функции, где каждая функция имеет подпись void func (void). Объявление *const означает, что сами указатели функций доступны только для чтения. Это означает, что они будут распределены во флэш-памяти, как это необходимо для векторной таблицы. Векторные таблицы обычно выделяются фиксированным зарезервированным адресом во флэш-памяти.

красивее способ, чтобы написать тот же код будет таким:

typedef void (isr_t)(void); 

isr_t* const [] = { 
    (isr_t* const)((uintptr_t)&__STACK_END), // The initial stack pointer 
... 

uintptr_t является достаточно большой целочисленный тип, гарантированно иметь возможность содержать адрес, в отличие от unsigned long.

Смежные вопросы