HOWTO · Arduino
Arduino の配列の長さ
Arduinoで固定長配列の要素数を求める方法を、配列全体と1要素のバイト数を使う `sizeof` 演算子の式とともに説明します。
このページの内容
Arduinoの固定長配列は、配列全体が参照できるスコープ内で sizeof(array) / sizeof(array[0]) を使って要素数を求められます。結果は要素数なので、ループの上限に使えます。sizeof() が測るのはバイト数です。この割り算で配列全体のバイト数を1要素のバイト数で割ることで、要素数が得られます。
sizeof() 演算子でArduino配列の長さを求める
たとえば、values に5個の整数が入っている場合、sizeof(values) / sizeof(values[0]) の結果は 5 です。この式が成り立つのは、この位置では values が配列全体を表しているためです。分母には配列の先頭要素のサイズを使うので、要素型が異なる別の固定長配列にも同じ式を使えます。
sizeof() の割り算が成り立つ理由
sizeof は関数ではなく、C++の演算子です。配列に適用すると、配列全体が占めるバイト数を示します。array[0] に適用すると、1要素が占めるバイト数を示します。前者を後者で割ると要素数が得られます。ただし、どちらの式も実際の配列とその要素型を参照している必要があります。
たとえば、この式は固定長の float 配列にも使えます。特定のボードで float が何バイトかを決めつける必要はありません。配列と要素のサイズは同じ型とターゲットに基づいて求められるため、その比が要素数になります。4 のようなバイト数を固定値として書かないでください。ループに必要なのはバイト数ではなく要素数です。
ほかの配列型や次元にも式を適用する
要素型が変わっても式は変わりません。readings という配列なら、sizeof(readings) / sizeof(readings[0]) を使います。初期化する値の数を変えたときも、別途入力した数値ではなく、宣言された配列に応じて要素数が決まります。
2次元の固定長配列では、配列全体のサイズを先頭行のサイズで割ると行数が求められます。先頭行のサイズをその先頭要素のサイズで割ると列数が求められます。たとえば int matrix[3][4] では、sizeof(matrix) / sizeof(matrix[0]) が行数、sizeof(matrix[0]) / sizeof(matrix[0][0]) が列数です。これらの式で分かるのは宣言された次元であり、実行時に変化するコレクションの現在の長さではありません。
配列を関数に渡すときの長さの扱い
配列を関数の引数として渡すと、その引数は先頭要素を指すポインターとして扱われます。関数内の sizeof(parameter) が測るのは呼び出し元の配列全体ではなく、ポインターのサイズです。そのため、これを sizeof(parameter[0]) で割っても、元の配列の要素数は分かりません。
要素数は別の引数として渡し、ループの上限に使います。配列全体を参照できる呼び出し元で、次のように要素数を計算します。printValues(values, sizeof(values) / sizeof(values[0]))。これで関数は指定された数の要素を処理できます。複数の関数を経由して配列を渡す場合も、各関数が必要な情報を持てるよう、要素数と配列を一緒に渡してください。
sizeof の式が使えるのは、式の位置で完全な型が分かる固定長配列です。実行時に変化するコレクションや動的に確保されたコレクションの長さは追跡できません。その場合は、コレクション固有の長さ取得方法で要素数を保持するか、取得してください。
Arduinoスケッチ全体で配列の長さを使う
Arduinoスケッチでは、固定長配列をファイルスコープまたは setup() の中で宣言し、同じスコープで要素数を計算します。その数よりインデックスが小さい間、0 から順に繰り返せば、宣言された配列の範囲内で各要素にアクセスできます。以下のスケッチは、ボード上でArduinoの Serial を使います。通常のC++としてコンパイルするときは、小さなローカルの Serial 代替を使って、同じ setup() の処理を標準出力に表示できます。コードと出力例の Count: という表示ラベルは、コードのバイト列を保つため英語のままです。
#include <stddef.h>
#ifdef ARDUINO
#include <Arduino.h>
#else
#include <iostream>
class SerialPort {
public:
void begin(unsigned long) {}
void print(const char* value) { std::cout << value; }
template <typename T>
void println(const T& value) { std::cout << value << '\n'; }
};
SerialPort Serial;
#endif
int values[] = {10, 20, 30, 40, 50};
const size_t valueCount = sizeof(values) / sizeof(values[0]);
void setup() {
Serial.begin(9600);
for (size_t i = 0; i < valueCount; ++i) {
Serial.println(values[i]);
}
Serial.print("Count: ");
Serial.println(valueCount);
}
void loop() {
}
#ifndef ARDUINO
int main() {
setup();
}
#endif
10
20
30
40
50
Count: 5
ボードにスケッチを書き込み、9600 baudに設定したシリアルモニターを開くと、値と要素数を確認できます。ループをヘルパー関数に移す場合は、配列とともに valueCount も明示的に渡してください。ヘルパー関数は、ポインター引数から元の配列の長さを復元できません。