型修飾子
C規格では、volatile および const は型修飾子です。
オブジェクトのvolatile宣言
オブジェクト volatileを宣言することによって、オブジェクトの値がコンパイラの制限以上に変化する可能性があることがコンパイラに伝えられます。またコンパイラは、あらゆるアクセスに副作用があると想定する必要があります。よって、volatileオブジェクトへのすべてのアクセスは保持されなければなりません。
オブジェクトをvolatileとして宣言する主な理由は、以下の3つです。
共有アクセス: マルチタスク環境で、オブジェクトを複数のタスクで共有する場合
トリガアクセス: メモリマップされた特殊機能レジスタ(SFR)のように、アクセス発生により影響が生じる場合
変更アクセス: コンパイラが認識できない方法で、オブジェクトの内容が変更される可能性がある場合
volatileオブジェクトへのアクセスの定義
C規格では、抽象マシンが定義されています。これは、volatile宣言したオブジェクトへのアクセスの動作を制御します。一般的に、抽象マシンに従うコンパイラの動作は、以下のとおりです。
volatileとして宣言されたオブジェクトへの各リード/ライトアクセスをアクセスと見なします。アクセスは、オブジェクト単位になります。複合オブジェクト(配列、構造体、クラス、共用体など)へのアクセスの場合は、要素単位になります。以下に例を示します。
char volatile a; a = 5; /* A write access */ a += 6; /* First a read then a write access */
ビットフィールドへのアクセスは、その根底型へのアクセスとして処理されます。
const修飾子をvolatileオブジェクトに追加すると、オブジェクトへのライトアクセスが不可能になります。ただし、オブジェクトはC規格で指定されたとおりにRAM内に配置されます。
ただし、これらの規則は大まかなもので、ハードウェア関連の要件には対応していません。 IAR C/C++ コンパイラ for Arm に固有の規則について、以下に説明します。
アクセス規則
IAR C/C++ コンパイラ for Armでは、volatileで宣言したオブジェクトは、以下の規則に従います。
すべてのアクセスが実行されます。
すべてのアクセスは最後まで実行されます。すなわち、オブジェクト全体がアクセスされます。
すべてのアクセスは、抽象マシンでの場合と同一の順序で実行されます。
すべてのアクセスはアトミックアクセスになります。すなわち、アクセス中に他の命令は生成されません。
コンパイラは、8ビット、16ビット、32ビットのすべてのスカラ型へのメモリアクセスに関して、これらの規則に準拠しています。ただし、パック構造体型のアライメントされていない16ビットおよび32ビットのフィールドへのアクセスは例外です。
記載されていないすべてのオブジェクト型の組合せについては、すべてのアクセスが維持されるという規則だけが適用されます。
オブジェクトvolatileおよびconstの宣言
volatile オブジェクトを const宣言する場合、書き込み禁止になりますが、C規格の仕様に従ってRAMメモリに格納されます。
代わりにリードオンリーのメモリにオブジェクトを格納して、const volatileオブジェクトとしてアクセス可能にするには、__ro_placement属性を使用して宣言します。__ro_placementを参照してください。
オブジェクトのconst宣言
const型修飾子は、データオブジェクト(直接またはポインタを使用してアクセス)がリードオンリーであることを示します。constとして宣言したデータへのポインタは、定数と非定数の両方のオブジェクトを参照できます。可能な限りconstとして宣言したポインタを使用することをお勧めします。これにより、コンパイラによる生成コードの最適化が改善され、誤って修正したデータが原因でアプリケーションに障害が発生する危険性が低下します。
constとして宣言した静的オブジェクトやグローバルオブジェクトは、ROMに配置されます。
C++では、ランタイムの初期化が必要なオブジェクトはROMに配置できません。