エキスパートCプログラミング

エキスパートCプログラミング―知られざるCの深層 (Ascii books)

エキスパートCプログラミング―知られざるCの深層 (Ascii books)

本日ぱらっと読んだところをメモ。

P243 なぜCは、引数中の配列をポインタとして扱うのか?

そもそも、なぜ配列は値渡ししないのか?
配列以外のデータ引数は「値渡し」される。
配列をコピーするのはメモリ効率の面でも実行時間の面でも非常にコストがかかる可能性がある。
そしてたいていの場合にはその時点で注目している配列を関数に伝えたいだけで、配列をコピー
して渡したい場合は滅多にない


解決策として

Pascalのように値渡しと参照渡しのどちらかを使うか、パラメータの記憶クラスを指定できるようにするという
ことも考えられる。
しかし、

コンパイラの単純化という点では、配列は常に先頭へのポインタとして渡すか、常にそのコピーを
渡すか、どちらかに決まっているほうがいい。

同様に、関数の戻り値でも配列や関数を返すことはできない。そのポインタだけが許されている。


まとめると

・メモリ効率
・実行時間
・コンパイラの単純化

以上の理由から
Cでは原則としてすべて値渡しとなっているが、配列と関数だけは例外で参照渡しになっている。

パラメータにおける配列とポインタの等値性は、効率のために採用された仕様。

P245

関数の引数として指定されたすべての配列は、コンパイラによってコンパイル時にポインタに変換される。
したがって関数内での引数の配列へのアクセスは、すべてポインタへの参照のコードになるのだ。

P54 unsigned型について一言

不必要にunsigned型を使って、無用の複雑さを持ち込まないこと。
特に、表現する値が負になることはないという理由だけでunsigned型を使わないこと。
intのような符号付きの型を使えば、複数の型を混在させたときの「格上げ」の規則で煩わされずに済む。
unsigned型を使うのは、ビットフィールドやバイナリのマスクだけに限ることだ。式にキャストをかけて
全オペランドを符号付か符合無に統一すれば、コンパイラは式の結果の型を作り出さずに済む。

P55

#define TOTAL_ELEMENTS ( sizeof(array) / sizeof(int) )
//上は、次のように書き換える。
#define TOTAL_ELEMENTS ( sizeof(array) / sizeof(array[0]) )

こうしておけば、arrayの型が変更されても、#defineの定義は書き換えなくて済む。
→型変換に惑わされずに済む、という考え方からですね。


unsignedを調べた

unsignedを今日調べたのにはわけがあって、

if( *(cRam+0) < 0 || *(cRam+0) > 23 ) 

上記のソースでずっとWARNINGが消えなくて、
よく見たら宣言が

unsigned char	_far	*cRam;

であったというオチ。