sizeofを使用する
| 設計内容分類 | 組み込みソフトウェアにおけるC言語記述 |
|---|
実現したい仕様・課題
配列サイズやバッファ長、型のバイト数をコード中に数値で直書きすると、サイズ変更時の修正漏れが不具合につながります。またintなどの型サイズは処理系依存であり、バイト数を決め打ちしたコードは別のマイコンへ移植した際に誤動作します。サイズ指定を安全で移植性のある形にしたいというのが課題です。
設計のポイント
sizeof演算子を使用することで、指定した型のバイトサイズを取得できます。また、変数(配列や構造体)を指定することで、その総バイト数を取得することもできます。memsetやmemcpyのサイズ指定には、数値の直書きではなくsizeofを使うことを基本とします。memset(array, 0x00, sizeof(array)); と書けば、配列サイズを変更してもこの行は修正不要で、常に正しいバイト数が渡ります。256 * sizeof(int) のように要素数×型サイズで書く方法もありますが、変数名だけで完結するsizeof(array)のほうが修正漏れの余地がありません。配列の要素数が必要な場合は sizeof(a) / sizeof(a[0]) で求められ、要素の型を変更しても追従します。注意すべき点として、関数の引数として受け取った配列はポインタに退化するため、sizeofはポインタのサイズ(4や8)を返してしまいます。配列を関数へ渡すときは、サイズを別引数で一緒に渡す設計とします。また、構造体のsizeofはパディングを含んだ実サイズを返すため、通信フレーム構造体が意図したサイズになっているかの検証(packed指定の確認)にも活用できます。型サイズの決め打ちをなくすことは、マイコン変更・コンパイラ変更に強いコードへの第一歩です。
【コード例】
int array[256];
memset(array, 0x00, 256 * sizeof(int)); // 型サイズをsizeofで
memset(array, 0x00, sizeof(array)); // 配列全体ならこちらが安全
#define ARRAY_NUM (sizeof(array) / sizeof(array[0])) // 要素数
// 注意:引数の配列はポインタに退化する
void func(int a[]) {
// sizeof(a) はポインタのサイズになる(配列サイズは別引数で渡す)
}
補足情報
設計のポイント 一覧
組み込みソフトウェアにおけるC言語記述のポイント
- リングバッファで受信データを取りこぼさない
- switch-caseによるステートマシンの実装
- 割り込みハンドラは短く書く
- constを活用する(ROM配置と書き換え防止)
- ビット演算によるレジスタ・フラグ操作
- 固定幅整数型(stdint.h)を使う
- volatile修飾子を正しく使う
- 構造体の宣言にpackedを指定する
- ソースコードのエンディアン変換
- sizeofを使用する
- 特殊文字の記述にエスケープ文字を使用する
- 変数の初期化漏れを防ぐ
- 外部バスの使用
- sprintf関数を使う
- 列挙型(enum)を使う
- 構造体を使う
- 標準関数を使う
- 条件演算子を使う
- インクリメント演算子を使う
- C言語記述の際はアプリ層とドライバ層に分ける



