組み込み屋さんになってやらかしたこと
かなりの内輪ネタ&恥さらしです。
すごい初歩的なミスなのかもしれないけど、自分が失敗から学んだ事をまとめてみます。
ご笑覧くだされば幸いです。
固定長の変数は一度別名で再定義する
例えば、下のようなコードを「type.h」とかいう名前で保存しておく。
typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned int UINT32; typedef unsigned long long UINT64;
で、プログラム中の固定長変数は上記のUINTxxを使って記述する。
組み込みだと、ハードの都合でいきなりマイコンを変更する、という事態があります。
時には32Bitマイコンから16Bitマイコンに変更、なんてことも。
C言語では、char以外の型のサイズは実装系依存ですので、ソースコード中に直接型名を埋めると、すべての変数の型を見直さなければなりません。
上記「type.h」を作っておけば、それぞれの元の型名を修正すれば良い、ということになります。
一度、手を抜いてコードに直接型名を埋めたことがあって、泣きながら全コードgrepしました(^^;
エンディアンを意識する
組み込みに限った話ではなく、バイナリ解析するようなプログラムを書くときは常に必要ですね。
バイナリに構造体を被せて扱うような場合があります。
typedef struct { UINT32 index; UINT16 count; UINT16 total; } DATA_HEADER; BOOL isPreviousData(UINT8* data) { DATA_HEADER* p = (DATA_HEADER*)data; return (p->index < 10); }
上記isPreviousData関数は、引数dataが示すバイナリデータと処理系のエンディアンが一致していないととんでもないことになります。
一致しない場合は、エンディアン変更するCONVERT_UINT32マクロかなんかを作って
BOOL isPreviousData(UINT8* data) { DATA_HEADER* p = (DATA_HEADER*)data; #ifdef LITTLE_ENDIAN CONVERT_UINT32(&(p->index)); #endif // LITTLE_ENDIAN return (p->index < 10); }
とするか、あるいは地道に変数代入をして
BOOL isPreviousData(UINT8* data) { UINT32 index; index = (data[0]) | (data[1] << 8) | (data[2] << 16) | (data[2] << 24); return (index < 10); }
とするか、ですね。
他に良い方法があったら、誰か教えてください(^^;
ペリフェラルへのアクセスはvolatile修飾子を使う
普通にPC上でプログラムを組んでいると、ほとんど使うことのない修飾子「volatile」。
組み込みでは大活躍です。
以下のサイトにすばらしい解説があるので、詳しくはそちら参照。
http://proger.blog10.fc2.com/blog-entry-20.html