— (decrement) の解説と実装リファレンス
【概要】
-- 演算子は、C/C++言語(Arduinoの基盤言語)において、変数の値を1減らすための単項演算子(Unary Operator)です。この演算子は、変数の値を更新すると同時に、その結果を式の中で利用することを可能にします。Arduinoプログラミングにおいては、ループカウンタ、タイマーのカウントダウン、ポインタの移動など、リソース制約の厳しい環境での効率的な数値制御に頻繁に使用されます。
【仕様】
-- 演算子には、前置(Prefix)と後置(Postfix)の2種類の用法があり、それぞれ動作と評価順序が異なります。
| 形式 | 構文 | 動作原理 | 戻り値 |
| 前置 | --x | 変数 x の値を先に1減らし、減らした後の値を返す。 | 減算後の値 |
| 後置 | x-- | 変数 x の現在の値を返し、その後に値を1減らす。 | 減算前の値 |
- 対象データ型:
int,long,byte,uint8_t,float,double等。 - 初期状態: 演算子自体は状態を持たず、操作対象となる変数の現在の値に依存します。
【技術的特徴】
- アセンブリレベルの最適化:
多くのマイコンアーキテクチャ(AVR, ARM等)において、--演算子は専用の命令(例:DEC命令)にコンパイルされることが多く、x = x - 1という算術演算と比較して、レジスタ操作の効率性が高い傾向にあります。 - 後置演算子のオーバーヘッド:
後置演算子x--は、「現在の値を保持する一時的なメモリ/レジスタ」を確保する必要があるため、コンパイラの実装によっては前置演算子よりも僅かながらコストがかかる場合があります。 - ポインタ演算との関連:
ポインタ型に対して--を適用すると、型(sizeof)に基づいて適切なバイト数分だけメモリ番地を逆方向に移動させます。
【注意点】
- アンダーフロー(Underflow):
符号なし整数型(uint8_t,unsigned int等)に対して0の状態で--を実行すると、型の最大値にラップアラウンド(巻き戻り)が発生します。例:uint8_t型の0を--すると255になります。これは、無限ループやバッファオーバーランの原因となるため、極めて注意が必要です。 - 原子性(Atomicity)の欠如:
--演算子はアトミックな操作ではありません。マルチスレッド環境や、割り込み(ISR)の前後で共有変数を操作する場合、読み取りと書き込みの間に割り込みが入ると、値の不整合が発生する可能性があります。共有変数の操作にはvolatile修飾子やクリティカルセクションの確保が必要です。 - 浮動小数点数への適用:
float型に対する--は、精度の問題により「常に1減る」ことが保証されない場合があります。厳密なカウントが必要な場合は整数型を使用するのが定石です。
【サンプルコード】
void setup() {
Serial.begin(9600);
}
void loop() {
uint8_t counter = 5;
Serial.print("Initial: ");
Serial.println(counter);
// 前置演算子の例
Serial.print("Prefix --counter: ");
Serial.println(--counter); // 4が表示され、counterは4になる
counter = 5;
// 後置演算子の例
Serial.print("Postfix counter--: ");
Serial.println(counter--); // 5が表示され、その後counterは4になる
Serial.print("Value after postfix: ");
Serial.println(counter); // 4が表示される
while(1); // 停止
}
【活用例】
- ダウンカウントタイマー:
LEDを一定時間点滅させるためのカウントダウン処理。while(timer--)のような記述で、カウントと条件判定を同時に行います。 - ポインタによるバッファ走査:
受信バッファの末尾から逆方向にデータを処理する際、ポインタをデクリメントしながらアクセスします。 - 状態遷移マシン(FSM):
特定の状態を終了させる際のステップカウンタの管理。


コメント