HOWTO · Arduino

Arduino の memset() 関数

Arduino の `memset()` で指定した範囲のバイトを埋める方法と、配列の要素を値で設定する方法を説明します。

このページの内容

memset() は、宛先アドレスから指定したバイト数分、同じバイト値を書き込みます。配列を埋めるバイト数は sizeof で計算できます。数値の各要素に値を設定したい場合は、型付きの代入を使います。

Arduino の memset() 関数

Arduino の C++ では、memset() は連続するバイト範囲を同じバイト値で埋めます。バイトバッファや文字配列に便利ですが、複数バイトの値を各要素へコピーする関数ではありません。第 3 引数はバイト数なので、実際に埋める領域のサイズを計算してください。

標準関数の宣言は <string.h> にあり、C++ のヘッダー <cstring> からも利用できます。形式は memset(destination, value, byte_count) です。destination は先頭バイトを指し、value は符号なしバイト値に変換され、byte_count は書き込むバイト数を指定します。変換後の 1 バイトが繰り返し書き込まれ、元の値のバイト列が取り出されるわけではありません。

Arduino の memset() 関数の使い方

次の C++ の例では、文字配列を埋めたあと、その一部を書き換えます。ボード固有のシリアル接続に依存せずバイト操作を示すため、標準出力を使っています。

#include <cstring>
#include <iostream>

int main() {
  char letters[] = "hello";
  std::memset(letters, '.', sizeof(letters) - 1);
  std::memset(letters + 1, 'a', 2);
  std::cout << letters << '\n';
  return 0;
}
.aa..

この配列には、5 文字と終端のヌル文字を格納する領域があります。最初の呼び出しは表示される 5 文字分のバイトだけを埋めるため、終端文字はそのまま残ります。2 回目はインデックス 1 から 2 バイトを書き込むので、インデックス 1 と 2 が変わります。Arduino スケッチでも同じ配列操作に memset() を使えます。結果の文字配列を表示するには Serial.print() を使ってください。

要素型が異なる配列では、配列そのものからバイト数を求めます。たとえば memset(values, 0, sizeof(values)) は values の全バイトを埋めます。要素単位の範囲を埋めるには、要素数分だけ宛先を進め、要素サイズを掛けてバイト数を指定します。例: memset(values + start, byte_value, count * sizeof(values[0]))。配列のインデックスは 0 から始まり、対象範囲が配列内に収まるようにしてください。

整数配列をバイト値 2 で埋めても、各要素に整数値 2 が代入されるわけではありません。int が 16 ビットでリトルエンディアンのターゲットでは、各 2 バイトが 0x0202 となり、値は 514 になります。整数の幅や表現が異なるターゲットでは結果も変わります。各要素に型付きの値 2 を代入するには、たとえば for (int i = 0; i < count; ++i) values[i] = 2; のようなループを使います。

Arduino の String の文字を変更するには、text[i] = '.'; のようにインデックスで文字を直接代入できます。これは文字への直接代入であり、memset() の使用例ではありません。

重要な注意点

宛先が書き込み可能な領域を指しており、バイト数がその領域のサイズ以内であることを必ず確認してください。配列を指す式に対しては sizeof(array) で配列全体のバイト数を取得できますが、配列として宣言された関数引数はポインターです。そのため、長さを別途渡すか計算してください。バイト数が 0 なら書き込みは発生しませんが、関数の契約上、宛先には有効なポインターが必要です。

同じバイトパターンを書き込む方法は、オブジェクトに値を代入する一般的な手段ではありません。文字バッファを埋める、またはバイトをクリアするなど、そのバイト表現を意図している場合に適しています。リソースを管理するオブジェクトや、コンストラクターや不変条件に依存するオブジェクトなど、非自明な C++ オブジェクトの初期化には使わないでください。通常の値やオブジェクトには、型付き代入、値初期化、またはオブジェクトが提供する API を使います。

まとめ

既知のバイト範囲を同じ値で埋めるときに memset() を使います。範囲のサイズはバイト単位で計算し、配列要素を扱うときは要素の幅を考慮して、書き込みが領域内に収まるようにしてください。整数値、文字列、オブジェクトには、特定のバイトパターンが必要な場合を除き、型付き代入や適切な初期化方法を選びます。