■Contents
コーディング規約
if(条件)文の書き方
データ圧縮
演算を高速に
条件マクロの多いソースを読みやすく
makefileの依存関係を自動生成&makefile雛形
ビットを扱う
ソフトウェアの解析術
このページで使用するmakefile
割り算と掛け算
defineとconstの違い
役に立つ書籍


ページ先頭へ

■if(条件)文の書き方
  • 範囲指定の書き方
    多くの方は、変数を左辺、定数を右辺に書く方が多いように感じます。
    ただ、範囲指定の場合、どちらが見やすいでしょうか?
    ・if( val >= 0 && val < 100 ){ ...
    ・if( 0 <= val && val < 100 ){ ...
    多くの方は、下の例のほうが見やすいと感じたはずです。
    あまり固定概念にとらわれることなく見やすいコードを書きたいものです。
  • エラー?仕様?
    時折、エラーなのか仕様なのか分からないコードを書く人がいます。
    ・if( val = 1 ){ ...
    ==を書き間違えたのか?、コードを記述した方しか、仕様なのかまったく分からないですよね。
    実際のデバッグ作業では、この不具合を特定するのに相当の時間を要するケースがあります。
    下のように書いたらどうでしょうか?
    ・if( 1 = val ){ ...
    コンパイルしてみると分かりますが、コンパイルエラーになります。
    勿論、==にすれば、正常にコンパイルできます。
    if文の定数は左辺に記述するように心がけていれば、こんなことはなくなりますね。
    心がけるだけで実際に書かなくても、だいぶ違うものです。

ページ先頭へ


ページ先頭へ

■データ圧縮
プログラムを作成していると、データが増えてきて、ROMが足りない!!ということになるケースがあります。そんなときは、データを圧縮してしまいましょう。
データにもよりますが、簡単な圧縮法、例えば、HUFFMAN圧縮でも、70%程度まで圧縮可能です。
圧縮法については、圧縮法入門を参照すると、沢山の方法が説明されています。プログラミングコスト、デバイスコストを見極めて最適な圧縮法を選択してください。
参考文献:C言語による最新アルゴリズム事典(技術評論社)

ページ先頭へ


ページ先頭へ

■演算を高速に
普通に演算を行うと、組み込み環境では、非常に時間がかかります。
そこで、以下のような方法を用いることで、高速化が可能です。
  • 2の倍数の場合の割り算
    1ビット右シフトすると、/2と同じです。2ビットだと/4、3ビットだと/8、つまり、2のn乗のnの分だけ右シフトすればよいわけです。
    ちなみに、掛け算の場合は、左シフトでOKです。
  • 2の倍数で割り算する場合の余りがあるかを判定
    通常だと、"%"演算子に相当します。割り算に似た考え方ですが、
    数字&(n-1)、但し、nは、割り算する数値
    結果がゼロならば、余りがゼロです。
  • 浮動小数点の演算
    組み込みで普通に小数点付きの数値演算を行うことは、一般的ではありません。
    多くの場合、他のメンバがライブラリとして用意していることでしょう。もしも、そんなことする必要があるの?という場合は、その人には聞かないほうが賢明です。教えてあげても良いでしょう。
    簡単な手法としては、必要な有効桁数だけ、ゼロを増やして、整数型で演算する。
    というのが、多いでしょう。
    以下に、例を挙げておきます。
    // child=1,parent=6,resolution=1000を指定すると、
    // 167が返ってくる
    // resolutionで割ると、0.167が得られる
    // 但し、child<=(ULONG_MAX/mag)でchildを指定すること
    // 上記条件を外れる場合、工夫が必要です。
    unsigned int int_div(
    	const unsigned long resolution,
    	const unsigned long child,
    	const unsigned long parent
    	)
    {
    	unsigned int d;
    	const unsigned long mag = (resolution<<1);
    	d = (unsigned)((child*mag)/parent);
    	return( (d+1)>>1 );
    }
      
    最初にresolutionを2倍しているのは、四捨五入するためです。


ページ先頭へ


ページ先頭へ

■条件マクロの多いソースを読みやすく
大きなプロジェクトでは、条件マクロが多くて読みにくい場合があります。
こんな時は、プリプロセッサを使いましょう。
gccだと、gcc -E -C ソースファイル名
でOKです。標準出力に表示されますので、必要に応じてリダイレクトなりすればよいです。
カレント以外の位置にヘッダファイルがある場合、-Iで位置を指定する必要があります。

ちなみに、UNIX用のEmacs系エディタ(WindowsならMeadow)では、リージョンを選択してから、M-x c-macro-expand を実行することで、表示できるので、非常に便利です。
場合によっては、.emacsに以下の記述をしないと動かないかも知れませんので、ご注意を。さらに、Windowsの場合は、Cygwinをgcc付きでインストールしておく必要があります。
(setq c-macro-preprocessor "cpp -C -E -Iインクルードファイルへのパス")
Windowsのメモ帳系エディタ(秀丸エディタなど)をお使いの方には、取っ付きにくいかもしれませんが、過去にMS-DOSでMIFESやVzを使っていた方なら、バリバリ使いこなせるはずです。実際私もそうでした。環境を整えるまで時間がかかりますが、一度はまると抜けられない感覚を味わえるかと思います。

ページ先頭へ

 
 
 
 

ページ先頭へ

■makefileの依存関係を自動生成
お知らせ makefileのページを作成しました。
makefileの基本を押さえたい方は、ご利用ください。
makefileの依存関係を手書きで書いているのをよく見かけますが、自動生成可能です。
多くのコンパイラ(実はプリプロセッサ)では、
  • -M
  • -MM
のどちらか、または両方が用意されている場合が多いです。
マニュアルでは、プリプロセッサの項目に記載されている場合が多いです。
一度、お使いのコンパイラのマニュアルを見てみては如何でしょうか。
マニュアル等に記載がない場合でも、使用できる場合もありますので、一度お試しを。
また、Windows環境でもCygwinを利用すれば、gccが使えますので、依存関係部分だけをgccに任せてしまう、という手もあります。
gccの場合、gcc -MM ソースファイル名
で依存関係が標準出力に表示されます。必要に応じてリダイレクトなりすればよいでしょう。
ちなみに、gccの場合、拡張子はデフォルトで.oになっていますので、他の拡張子にしたい場合は、sedとgrepを組み合わせればOKです。
sedはsオプション、grepはvオプションを使用します。
これを流用すると、特定のファイルを依存関係に含めないようにすることも可能になります。

参考書籍:
一押しは、Make―C programming utilityです。(make改訂版の新版のようです)
また、makefileとは無関係ですが、組込みソフトウェア開発における品質向上の勧め (コーディング編)もお勧め。最近バグの多い情報機器の開発者には是非とも読んでほしい一冊。

これで、ヘッダを修正したらmake cleanしてね、というのをしなくてよくなります。

自動化すると、以下のようになります(プログラム研究所より引用)

汎用的なmakefileの一例(単一ターゲット)
上のmakefileは、
  • SRC=で定義されたCソースファイル
  • HEADER=で定義されたCヘッダファイル
  • makefile本体
のどれかのファイルに変更があった際に、
TARGET=で定義された実行ファイルを作成する
makefileの一例です。

環境は、CygwinのGCC環境を想定しています。
他の環境の場合は、若干の修正が必要かもしれません。

一応汎用的になっていて、
Cソースが追加になったら、SRC=とOBJ=に追加
Cヘッダが追加になったら、HEADER=に追加
するだけで大丈夫です。
但し、
特定のファイルに対して別のオプションでコンパイルしたい場合は、
そのファイルに対して、別途ルールを指定する必要があります。

使用方法は、makefile冒頭部分に記述してあるとおりです。
基本的には、コマンドラインから、"make"とするだけです。
Meadow/Mule/Emacsなどでは、
ソースファイルやmakefileのウィンドウにフォーカスを当てて、
M-x compile として、ミニバッファで、make、と入力すればOK

余談になりますが、C++を扱う場合の注意点は
  • CFLAGSではなく、CXXFLAGSにコンパイルオプションを指定する
  • CCではなく、CXXにコンパイラを指定する
これらに注意しておけば、基本的にはCと同じです。

GNU makeの日本語マニュアルがCOOPさんの部屋にあります。
作者に感謝し、おおいに活用させていただきましょう。

それでは、makefileなどに振り回されることなく、
プログラム開発に時間を費やしましょう。


ページ先頭へ


ページ先頭へ

■ビットを扱う
C言語では、ビットが扱いにくい、とお考えの方が多いようですが、工夫次第では改善できます。ここでは、構造体と共用体を組み合わせた方法を紹介します。

// gcc -obitfield.exe bitfield.c -Wall

#include <stdio.h>

typedef struct sBitField
{
	unsigned char a :1;
	unsigned char b :1;
	unsigned char c :1;
	unsigned char d :1;
	unsigned char e :1;
	unsigned char f :1;
	unsigned char g :1;
	unsigned char h :1;
}BITFIELD;
typedef union uUniBitField
{
	BITFIELD bf;
	unsigned char ch;
}UNIBITFIELD;

int main(void)
{

	UNIBITFIELD un;

	un.ch = 0;
	printf( "bf=%02xd\n", un.ch );

	un.bf.a = 1;
	printf( "bf=%02xd\n", un.ch );

	un.bf.e = 1;
	printf( "bf=%02xd\n", un.ch );

	un.ch = 0;
	printf( "bf=%02xd\n", un.ch );

	return( EXIT_SUCCESS );

}
こうすると、1バイト全体、ビット単体の変更、参照が行えます。

ページ先頭へ



defineとconstの違い

TOP

defineとconstの違い
ソース

makefile
このサンプルは、マクロ定義の括弧ありなしでどのような結果をもたらす可能性があるかを示したものです。
結果は、makeして、実行していただくと分かるのですが、
  • 9
  • 5
となります。
一方、constを用いた例では、両方とも、同じ結果が得られます。
これは、双方の特徴を大きく表しています。
無用なトラブルを避けるためにも、定数定義は、constを使用したいものですね。
割り算と掛け算

TOP

割り算と掛け算についての考察
割り算と掛け算は結構、奥が深いものがあります。まずは、サンプルプログラムをmakeして、実行してみてください。
  • example1
    整数の普通の割り算、結構な時間ですね
  • example2
    同じことをシフト演算を用いて行いました。この中では、最短です。よく知られたことですが、2の累乗(n)で割り算は、nビット右シフトすることで、得ることができます。
  • example3
    実数の割り算です。整数の1.5倍かかっています。使いどころを誤ると、大変なことになります。
  • example4
    整数の普通の掛け算、割り算と比べたらかなり高速です。
  • example5
    割り算と同じように左シフト演算を使うと、掛け算が行えるという例です。普通の掛け算より、15%ほど高速です。
  • example6
    実数の掛け算です。整数の割り算:整数の掛け算の比率と実数の割り算:実数の掛け算、の比率が大きく異なるところが面白いですね。
まとめると、実数の割り算>実数の掛け算>整数の割り算>整数の掛け算>左シフト=右シフト、となります。このデータから、何が得られるでしょうか。よーく、考えてみてください。アセンブラソースが読める方は、make asm、として、ソースを読んでみると、納得できますね。
整数の割り算と掛け算の実行時間が1/4になることを考えると、いろいろと考えが膨らんできますよね。
ファームウェアでは、これらのことを踏まえて、例えば、温度管理を予め100倍してテーブル管理したりしています。これで、簡単な高速化になります。

makefile

TOP

まずは、このページで紹介するプログラムの共通makefileを紹介します。
話しを単純化するために、ヘッダファイル等は、なしの状態で makefileの"APL="に単一ソースを指定することにします。
状況によっては、Win32APIを使用するケースもありますので、 この場合のみ、-mwindowsを指定することにします。


ページ先頭へ

■コーディング規約
コーディング規約とは、複数人でプロジェクトを運用する際に、主にメンテナンスのしやすさを目的として、プログラムの書き方を取り決めしておくことを言います。
この取り決めを全くしておかないと、特にC言語の場合、自由度がかなり高いため、プロジェクトリーダの方が他のメンバのソースコードを読んでから、「これじゃ駄目」「常識的でない」などと勝手なことを言ったりするものです。プロジェクトに参加する際は、まず、コーディング規約の有無を確認しておいたほうが無難です。結構、ワンマンなプロジェクトリーダは多いものです。
できれば、組込みソフトウェア開発における品質向上の勧め (コーディング編)を読んでおくとよいでしょう。特に、最近バグの多い情報機器の開発者には是非とも読んでほしい一冊。
もうちょっとまとまったのが欲しいという方は、
組込みソフトウェア開発向けコーディング作法ガイド
組込みソフトウェア開発向けコーディング作法ガイド

文字通り、コ−ディング作法について記述した書籍です。
高品質なC言語コーディングのためには、開発者の暗黙の了解でコードを記述するのではなく、コーディング規約を定め、規約に基づいてコードを記述することが有効です。しかし、コーディング規約を制定するためには、C言語の文法に精通している必要があることなど、高いスキルと多大な労力が必要です。また、開発者への理解を深め、普及・徹底を図ることに大きな障壁があることも事実です。本書は、C言語のコーディング規約を策定している方を対象にした「コーディング作法ガイド」です。本書は、品質特性に対応して分類した作法と、それに対応するルール群から構成されています。コーディング規約を策定する方は、ルール群の中から必要部分を取捨選択することにより、目的に見合ったコーディング規約を策定することが可能になりました。
規約 書き方 備考




ページ先頭へ

■役に立つ書籍

(データ提供:Amazon.co.jp)

ページ先頭へ




■お知らせと連絡先

このウェブサイトで取り上げて欲しい話題や分かりにくい点などありましたら、
以下のメールアドレス宛にメッセージをいただければ、参考にさせていただきます。

メールアドレスは、work_komiあっとまーくyahoo.co.jpです。
(「あっとまーく」は、半角英数のあっとまーくに変換してね。)

また、XBOXをお使いの方は、ゲーマータグ(akbox)にてフレンドリクエストを受け付けています。