2016-11-15 15 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の礼儀):ボイド


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

を返す関数へのconstポインタのアレイとして

宣言RVT(ボイド)ティsは配列のaggregate initialization [1]です。さらに、これはrvtの宣言が定義であることを意味します。


&__STACK_END 

addresof演算子は、変数のメモリアドレスをとります。

(unsigned long)&__STACK_END) 

アドレスがunsigned long型にキャストされます。

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

変換された値を再び配列に格納された関数ポインタの種類である、空隙返す(ボイド)を関数へのポインタにキャストされます。


配列の初期化された値の残りの部分は、いずれかの関数名、関数ポインタまたは暗黙的なラムダなどの関数ポインタに変換することができるものかもしれません。

+2

Cには "copy-list-initialisation"はありません。 – Olaf

+0

これは普通の古い配列初期化子リストです。コンストラクターは割り込みベクタテーブルなので、明らかに呼び出されず、 "lambdas"も呼び出されません。実行時に何も計算する必要はありません。 – Lundin

+0

@ Lundin私の答えを明確にするために、何も提供されていないので文脈がないものと仮定します。私は変数が何であるかは説明していません(私はそれを知らないので)。私はコードと文脈が与えられていないと、何ができるのかを記述します。あなたの最後の文については、実行時の開始時に定数が初期化されていないか(テーブルが静的であると仮定して)? – user2079303

1

引数をとらずにvoidを返す関数へのポインタの配列を定義します。次に、配列はメモリ内のいくつかのレジスタのアドレスで初期化され、関数ポインタにキャストされます。

埋め込みプログラミングに使用される割り込みベクタテーブルのようです。

+0

配列は確かにベクタテーブルですが、コンパイル時の定数と関数から初期化され、メモリのレジスタからは初期化されません。配列は読み取り専用なので、レジスタからの初期化はできません。 – Lundin

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

これは、 "rvt"という名前のconst配列を定義します。その要素は、引数のないvoid関数へのポインタです。

この配列は、中括弧初期化子リストで初期化されます。したがって、他のすべての行はこの配列の要素です。最初のものは__STACK_ENDへのポインタであり、明らかに型が間違っているため、正しい型にキャストする必要があります(まずunsigned longにキャストされ、次に正しい関数型ポインタにキャストされます)。

Btw:最後のコメントに閉じ括弧が含まれているため、中括弧が閉じられていないか、書式設定が間違っているため、コードが不完全ですか?

+0

'これは" rvt "という名前のconst配列を定義します。ここで' Array'は 'const'であり、' constポインタ 'ではありませんか? – Michi

+0

@Michi:はい。関数自体は暗黙的に定数です(関数自体に 'const'を適用することはできません)。関数(ポインタ)に 'typedef'を使用すると、より明確になります。 – Olaf

+0

@Olafそれも私のポイントでした。しかし、なぜこの答えが違うのですか? – Michi

0

これは、ARM Cortex Mマイクロコントローラの割り込みベクタテーブルのようです。他のほとんどのMCUに比べARMのCortex中

enter image description here

一つの特別な機能、それはプログラム開始前に設定し、スタックポインタを持っていることです。他の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_tunsigned longとは異なり、アドレスを保持することができるように保証、十分に大きな整数型です。

関連する問題