++ (increment) の解説と実装リファレンス
【概要】
++ 演算子は、C/C++ 言語(Arduinoの基盤言語)における単項インクリメント演算子です。指定された変数の値を現在の値から 1 加算する操作を指します。組み込みシステムにおいて、カウンタ、インデックスの制御、状態遷移の管理など、最も頻繁に使用される基本演算の一つです。
【仕様】
| 項目 | 内容 |
| 演算子種別 | 単項演算子 (Unary Operator) |
| 対象データ型 | int, long, uint8_t, float, double 等の数値型 |
| 動作原理 | 変数に格納されている現在の値に 1 を加算し、その結果を元の変数に書き戻す |
| 前置インクリメント (++i) | 値を 1 加算した後の値を評価する |
| 後置インクリメント (i++) | 値を 1 加算する前の元の値を評価し、その後に加算を行う |
【技術的特徴】
前置演算子 vs 後置演算子の差異
組み込み開発において、これら二つの動作の違いを正確に把握することは重要です。
– 前置インクリメント (++i):
評価式の結果として、更新後の値が返されます。メモリ効率の観点では、一時的なコピーを作成する必要がないため、最適化されたコンパイラでは後置演算子よりも高速に動作する場合があります。
– 後置インクリメント (i++):
評価式の結果として、更新前の値が返されます。内部的には「現在の値を保持する一時的な変数の作成」と「元の変数の更新」という2つのステップを伴うため、複雑な式で使用すると、わずかですが計算コストが増加する可能性があります。
ハードウェアレベルでの挙動
プロセッサレベルでは、この演算子は「ロード(メモリからレジスタへ)」「加算(ALU)」「ストア(レジスタからメモリへ)」の命令シーケンスとして実行されます。Arduino(AVR等)では、リソース制約があるため、効率的な命令セットへの変換が行われます。
【注意点】
1. オーバーフロー (Overflow)
変数のデータ型によって最大値が規定されています。例えば、uint8_t 型(0-255)で 255 の状態で ++ を実行すると、値は 0 にリセットされます。カウンタの実装では、このラップアラウンド挙動を考慮する必要があります。
2. 非原子性 (Non-atomicity)
++ 演算子はアトミックな操作ではありません。特に、割り込み処理(ISR)とメインループの両方で同じ変数を操作する場合、加算の途中で割り込みが発生すると、値の不整合(レースコンディション)が発生する可能性があります。この場合、volatile キーワードの付与や、割り込み禁止フラグの活用が必要です。
3. 未定義動作 (Undefined Behavior)
i = i++ のような、同一の式内でインクリメントと代入を同時に行う記述は、C言語の規格において未定義動作となる可能性があります。意図しない挙動を防ぐため、インクリメントと代入は分離して記述することが推奨されます。
【サンプルコード】
#include <Arduino.h>
volatile uint8_t counter = 0; // 割り込みを考慮したカウンタ
void setup() {
Serial.begin(9600);
}
void loop() {
// 前置インクリメントの例
for (int i = 0; i < 5; ++i) {
Serial.print("Pre-increment: ");
Serial.println(i);
}
delay(2000);
// 後置インクリメントの例
int j = 0;
Serial.print("Post-increment (initial value): ");
Serial.println(j++); // 0を表示した後、jは1になる
delay(2000);
}
【活用例】
- 状態遷移マシン (State Machine):
現在の状態(State)を数値で管理し、条件に応じてcurrent_state++を用いて次の状態へ遷移させる実装。 - パルス計測:
外部インターラプト(外部割り込み)が発生するたびに、特定の変数を++し、一定期間内のパルス数をカウントする。 - 配列のインデックス制御:
センサーデータの取得ループにおいて、配列のインデックスをi++で進めながらデータを格納・処理する。


コメント