前回の授業で、#defineマクロやbit演算の説明をしたけど、 まだ詰めが甘かったので、開いたサブルーチン・閉じたサブルーチンなどの 説明を行い、標準関数などの説明も行う。
開いたサブルーチンと閉じたサブルーチン
#define マクロと、関数の違いを理解してもらうために、 プリプロセッサ・コンパイル・リンクといった機械語生成までの流れを説明し、 #define マクロを多用すると、同じ機械語が何度も生成され、機械語が肥大する 可能性を説明する。逆に関数を何度も利用しても、一箇所の機械語が使われるため 機械語の肥大は無いことを説明する。一方、関数では実引数・仮引数の 値渡しなどが発生するので、わずかとはいえ余計な処理時間を要することを説明。 この結果、#define マクロは、小さな関数向きであることを述べる。 また、関数は入口・出口が明確に作られることから、閉じたサブルーチンと呼ばれる。 逆に #define マクロは入口・出口が明確でなく、開いたサブルーチンと呼ばれることを 説明する。
N進数変換や文字列処理で使う標準関数
N進数変換や文字列処理で、ctype.h の isdigit() 関数や、stdlib.h の strtol() などの 標準関数を説明する。
型の問題と実行時のトラブル
1桁の数値と+,-記号で式の値を求めるeval() という関数を示し、 文字列処理のサンプルを説明する。このあと、以下の様な呼び出しの問題点を考えてもらう。
int eval( char s[] ) { // 一桁の数値と"+","-"の計算式 // 例 printf( "%d" , eval( "1+2+3" ) ) ; // 6 } void main() { printf( "%d" , eval( 1+2+3 ) ) ; // 引数型の不一致 printf( "%d" , eval( '1+2+3' ) ) ; // 文字定数エラー printf( "%d" , eval( "1+2+3" ) ) ; // OK // よくありそうな書き間違い char s[ 100 ] ; scanf( "%s" , s ) ; printf( "%d" , eval( s[100] ) ) ; // 引数型不一致 // 文字列ポインタの間違い char* s ; scanf( "%s" , s ) ; // 変な場所に文字列格納でメモリエラー printf( "%d" , eval( s ) ) ; // char s[ 5 ] ; scanf( "%s" , s ) ; // 1+2+3+4+5+6 を入力したら!? printf( "%d" , eval( s ) ) ; }