C で が必要なのはなぜですかvolatile
? 何のために使用されますか? 何をするのですか?
ベストアンサー1
volatile
変数に関係するものを最適化しないようにコンパイラに指示しますvolatile
。
これを使用する一般的な理由は少なくとも 3 つあり、いずれも目に見えるコードからの操作なしに変数の値が変更される可能性がある状況に関係しています。
- 値自体を変更するハードウェアとインターフェースする場合
- 変数を使用する別のスレッドが実行されている場合
- 変数の値を変更する可能性があるシグナル ハンドラがある場合。
どこかの RAM にマップされ、コマンド ポートとデータ ポートの 2 つのアドレスを持つ小さなハードウェアがあるとします。
typedef struct
{
int command;
int data;
int isBusy;
} MyHardwareGadget;
ここで、何らかのコマンドを送信します:
void SendCommand(MyHardwareGadget* gadget, int command, int data)
{
// wait while the gadget is busy:
while (gadget->isBusy)
{
// do nothing here.
}
// set data first:
gadget->data = data;
// writing the command starts the action:
gadget->command = command;
}
簡単そうに見えますが、コンパイラはデータとコマンドの書き込み順序を自由に変更できるため、失敗する可能性があります。これにより、私たちの小さなガジェットは、以前のデータ値を使用してコマンドを発行することになります。また、wait while busy ループも見てください。これは最適化されます。コンパイラは賢く行動し、値をisBusy
1 回だけ読み取ってから無限ループに入ります。これは望ましくありません。
これを回避するには、ポインタgadget
を として宣言しますvolatile
。この方法では、コンパイラはあなたが書いたとおりに動作するように強制されます。メモリ割り当てを削除したり、レジスタに変数をキャッシュしたり、割り当ての順序を変更したりすることはできません。
正しいバージョンは次のとおりです:
void SendCommand(volatile MyHardwareGadget* gadget, int command, int data)
{
// wait while the gadget is busy:
while (gadget->isBusy)
{
// do nothing here.
}
// set data first:
gadget->data = data;
// writing the command starts the action:
gadget->command = command;
}