0

私のコードは C で書かれています。グローバル変数を使用してメイン コードと通信する ISR (割り込みサービス ルーチン) があります。ISR は、メイン コードとは異なるコンパイル ユニットにあります。メイン コードに「揮発性」を使用できないが、ISR では使用しない理由はありますか?

私の理由は次のとおりです。volatile 修飾子が、コンパイラによる ISR の完全な最適化を妨げています。ISR の観点からは、変数は揮発性ではありません。つまり、ISR の期間中は外部から変更できず、ISR の期間中は値を出力する必要はありません。さらに、ISR が独自のコンパイル ユニット内にある場合、コンパイラは ISR が最初に使用する前にメモリからグローバルを読み取らせなければならず (MUST)、戻る前に変更を保存し直さなければなりません (MUST)。これについての私の理由は次のとおりです。異なるコンパイルユニットを同時にコンパイルする必要がないため、コンパイラは ISR の範囲を超えて何が起こっているのかを認識できず (またはそのふりをする必要があります)、グローバルが read/ であることを確認する必要があります。 ISR の境界に書かれています。

おそらく、コンパイル単位の重要性を誤解していますか? 私が見つけた参考文献の 1 つは、GCC がこの揮発性の不一致をコンパイル時のエラーにしたと述べています。それらが異なるコンパイル単位にある場合、それらは独立しているべきではないのでしょうか。ライブラリ関数を個別にコンパイルして後でリンクすることはできませんか?

volatile を使用してシステム コードを解読する 9 つの方法

おそらく、シーケンス ポイントの概念から議論を行うことができます。シーケンス ポイントまたは副作用の概念を完全には理解していません。しかし、C99 仕様は 5.1.2.3 パラグラフ 2 で次のように述べています。 "

附属書 C には、以下を含むシーケンス ポイントがリストされています。

  • 引数が評価された後の関数の呼び出し。
  • ライブラリ関数が戻る直前。

参照: WG14 ドキュメント: N1013、日付: 2003 年 5 月 7 日

注: 前の質問、関数呼び出しと戻り値に関連するグローバル変数アクセスでは、関数呼び出しと戻り値の前/後にグローバルが格納/書き込まれるかどうかを尋ねました。しかし、これは別の質問であり、グローバル変数が異なるコンパイル単位で「揮発性」として異なって修飾される可能性があるかどうかを尋ねます。私は予備的な結論を正当化するために同じ推論の多くを使用したため、一部の読者は同じ質問であると考えるようになりました.

4

1 に答える 1

0

ISO/IEC 9899:2011 (C11 標準) は次のように述べています。

6.7.3 型修飾子

¶6 const修飾されていない型の左辺値を使用して、const修飾された型で定義されたオブジェクトを変更しようとした場合、動作は未定義です。volatile 修飾されていない型の左辺値を使用して、volatile 修飾された型で定義されたオブジェクトを参照しようとした場合、動作は未定義です。133)

133)これは、プログラム内で実際にオブジェクトとして定義されていない場合でも、修飾された型で定義されているかのように動作するオブジェクトに適用されます (メモリマップされた入出力アドレスのオブジェクトなど)。

¶6 の 2 番目の文は、ここに示す組織のいずれかを持っている場合、未定義の動作を呼び出すと述べています。

File main.c                             File isr.c:

volatile int thingamyjig = 37;          extern int thingamyjig;         // V1

extern int thingamyjig;                 volatile int thingamyjig = 37;  // V2

V1またはV2のいずれの場合でも、標準のそのセクションで指定されている未定義の動作に違反していますが、V1は質問で説明していると思います。

volatile修飾子は一貫して適用する必要があります。

File main.c                               File isr.c:

volatile int thingamyjig = 37;            extern volatile int thingamyjig;  // V3

extern volatile int thingamyjig;          volatile int thingamyjig = 37;    // V4

V3 と V4 の両方で、volatile 修飾子が一貫して保持されます。

「未定義の動作」の有効な表現の 1 つは、「正常に動作し、希望どおりに動作する」ことであることに注意してください。残念ながら、それが未定義の動作の唯一の、または必ずしも最も妥当な可能性のある兆候ではありません。危険を冒さないでください。首尾一貫してください。

于 2016-09-12T00:17:09.977 に答える