C プログラミング入門 基幹2 (月4) 14: 発展事項 Linux にログインし、以下の講義ページ を開いておくこと http://www-it.sci.waseda.ac.jp/ teachers/w483692/CPR1/ 2014-07-14 1 今日の内容 これまでの講義で説 明していない事項に ついて簡単に紹介す る 文法 標準入出力ファイル 異常終了 短絡評価 文字定数の型 キャスト 変数の宣言位置 グローバル変数 2014-07-14 静的変数 (static) const 変数 プリプロセッサ・ディレクティブ マクロ (ファイルの読み込み) (数学関数のエラーチェック) (関数ポインタ) (可変長引数) プログラミング技術 モジュールプログラミング 外部リンケージ アサーション C プログラミング入門 基幹2 (月4) 2 文法 2014-07-14 C プログラミング入門 基幹2 (月4) 3 標準入出力 標準入力、標準出力はファイルの一種 それぞれ stdin, stdout という FILE ポインタが グローバル変数で定義されている たとえば printf("Hello!"); は <stddef.h> で定 fprintf(stdout, "Hello!); と同じ 義されているが、 標準エラー出力というのもある <stdio.h> などで 読み込まれている fprintf(stderr, "Memory error\n"); 標準出力とは区別されていて、エラーを知らせる 時に使う。標準出力がリダイレクトされてもエラー は画面に出る 2014-07-14 C プログラミング入門 基幹2 (月4) 4 正常終了・異常終了 main() から return で終了した場合を正常終 了という 標準ライブラリ関数 exit() を使っても同じ 終了時に自動的に呼ばれる関数を atexit() で登 録することができる OS による検出などで強制的に終了すること を異常終了という プログラムから意図的に行うには abort() を用い る シグナルをトラップして処理できる(詳細略) 2014-07-14 C プログラミング入門 基幹2 (月4) 5 短絡評価 論理演算子の最初の式から全体の値が決まる場合、 2つ目の式を評価しない (式1) && (式2) : (式1) が偽の場合、(式2) を評価し 式全体として偽となる ない (式1) || (式2) : (式1) が真の場合、(式2) を評価し 式全体として真となる ない たとえば、以下のような場合に意味を持つ if(p != NULL && p[0] == 3) … もし p が null ポインタの場合、 p[0] は評価できないが、 短絡評価されるので問題ない 2014-07-14 もちろん、 if(p != NULL) { if(p[0] == 3) ... } と書いてもよい C プログラミング入門 基幹2 (月4) 6 文字定数の型 文字定数 (文字リテラル) は char 型ではなく、 int 型である 例: 'A' は ASCII コードでは int の 65 標準ライブラリ関数で文字を扱う関数では、 文字を指定するのに int 型となっている 例: 指定した文字 ch を文字列 str から見つける char *strchr(const char *str, int ch); C++ では、文字リテラルは char 型である 2014-07-14 C プログラミング入門 基幹2 (月4) 7 キャスト 数値を任意の型に強制的に変換する 変換されるものに対して挙動が異なる 演算子の一種 構文: (型)値 キャストの例 const を使う 意義がなくな るので、やる べきではない (int)4.5 4.5 を 4 に切り捨てる (int *)p ポインタの型を変える const 型を非 const 型に変更することもできる キャストはバグの温床なので多用しない () はいろいろなところで使われるので検索で見つ けづらい 2014-07-14 C プログラミング入門 基幹2 (月4) 8 ローカル変数の宣言位置 C89 まではローカル変数 は必ずブロックの先頭で 宣言する必要がある C99 以降はどこでも可能 になった { // int sum = 0; ... 長いプログラム ... 2014-07-14 ここでは sum は全 く使われ ない int sum = 0; GCC は標準で許容 C++ の文法を導入したもの 使用する直前で宣言する ほうがコードが読みやす い ここで定義す るよりは… int i, j, k; for(... { } } sum += s[i]; ここで定義す ... れば、ここか ら始めて使わ れることがわ かる C プログラミング入門 基幹2 (月4) 9 グローバル変数 関数の外で宣言される変 数 宣言位置以降どこでも可視 初期化がない場合、 0 に初 期化される ソース全体の定数などに 利用 デフォルトで外部リンケージを持つため、 ほかのプログラムとの共有をしない場合 は static を付ける。詳細略 2014-07-14 #include <stdio.h> const int PI = 3.1415; int count; int func1(void) const を付けて、 { 定数として使う ... } 実行開始時に 0 に初期化される int main(void) { ... } C プログラミング入門 基幹2 (月4) 10 関数内の static 宣言 関数の変数宣言に static を付けるとグローバル変 数と同様にプログラムの 開始時から終了まで生存 する変数となる スコープはその関数のみ 初期化を指定しない場合 0 に初期化される 書かなくても 0 #include <stdio.h> に初期化される int count(void) { static int n = 0; ++n; return n; 呼び出すたびに 1 増える } int main(void) { printf("%d\n", count()); グローバル変数に対する static とは効 果が異なる printf("%d\n", count()); ... 2014-07-14 C プログラミング入門 基幹2 (月4) 11 変数とポインタと動的メモリ確保の整理 再掲 分類 生存期間 スコープ メモリ領域 初期化 自動変数 (ローカル変数) 定義位置から ブロック終端 まで 定義位置か らブロック 終端まで スタック 初期化が指定されている場 合のみ、ブロックに入るた びに初期化される 大域変数 (グローバル変数) プログラムの 実行開始から 終了まで 定義位置か らプログラ ム終了まで 静的領域 プログラム開始時に1度だ け。初期化が指定されない 場合、0 で初期化される 静的変数 (static 変数) プログラムの 実行開始から 終了まで 定義位置か らブロック 終端まで 静的領域 同上 動的メモリ 確保から解放 まで ヒープ malloc() はされない calloc() は 0 を書きこむ 2014-06-23 C プログラミング入門 基幹2 (月4) 12 プリプロセッサとディレクティブ # で始まるものは、プログラムのコンパイル 前にプリプロセッサというソフトで処理され る。これをディレクティブという #include によるヘッダファイルの読み込みや #define のマクロなどはこれの一種 #if, #ifdef, #ifndef, #endif, #define, #undef, #line などがある 詳細は、リファレンスサイトで調べてください。 2014-07-14 C プログラミング入門 基幹2 (月4) 13 マクロ 主に定数を書く際に用いられる 通常のマクロと、関数型のマクロがある どちらも #define ディレクティブで定義する 例 間に = を書かない 最後にセミコロンは付けない #define MVAL 100 ソースコード中のすべての MVAL を、文字列 100 で置き換える 多くの場合マクロを使わず、グローバル変数 を書くべき 関数の外で書く static const int MVAL = 100; 2014-07-14 値の型が必要 C プログラミング入門 基幹2 (月4) 14 マクロ 標準ライブラリでは、定数の多くがマクロで 定義されている 例 RAND_MAX 乱数の最大値 EXIT_SUCCESS, EXIT_FAILURE return の後に 0 や 1 を書く代わりに使う ERANGE EOF 2014-07-14 数学関数のエラーコード ファイルの終端 C プログラミング入門 基幹2 (月4) 15 関数型マクロ 関数型マクロは、関数の様に引数を与えるこ とができる 特に理由がない限り、普通の関数を使うべき 標準ライブラリ関数のいくつかはマクロである 例 #define xy2idx(x,y,w) ((x)+(y)*(w)) いつも決まった式を書く場合に便利 単純なソースコード上の文字列の置 き換えになるので、解釈がおかしく ならないように、引数それぞれと、 式全体に括弧を付ける 2014-07-14 C プログラミング入門 基幹2 (月4) 16 関数型マクロ 標準ライブラリの関数型マクロの例 getc(fp) assert(exp) 2014-07-14 fgetc(fp) と等価 exp が偽であれば異常終了する C プログラミング入門 基幹2 (月4) 17 プログラミング技術 2014-07-14 C プログラミング入門 基幹2 (月4) 18 const コレクトネス 関数の引数がポインタであり、それを通して 値を変更しない場合は常に const を付ける (説明済み) ローカル変数で変更をしないものには常に const を付ける コンパイラによる最適化(高速化)が期待で きる 2014-07-14 C プログラミング入門 基幹2 (月4) 19 アサーション(表明) (assertion) ソースコード中で、 常に成り立つ条件を コードで表す コメントで書くよ り効果的 #include <stdio.h> assert マクロを使う 条件を満たさない場合、 異常終了する 常に条件が満たされる ようにコードを書く #include <assert.h> // n 要素の int 配列 a の総和 int sum(const int *a, int n) { int s = 0, i; assert(n > 0); assert(a != NULL); for(i = 0; i < n; ++i) { プログラムのバグがない ⇒ 全てのアサーションが真 } 2014-07-14 条件を満たさない s += a[i]; 限り以降の処理が } 正しく行われない ので、絶対に進ま return s; せない C プログラミング入門 基幹2 (月4) 20 アサーションの無効化 条件判断には計算時間がかかるため、リリー ス製品のような場合には無効化する NDEBUG マクロを定義すると、条件式が空行に置き 代わる gcc では、コンパイル時に -DNDEBUG オプション を付ける 2014-07-14 C プログラミング入門 基幹2 (月4) 21 アサーションの考え方 バグのないプログラム⇒全てのアサーション が真 プログラマは、アサーションに違反しないように 関数を呼び出すことを強制される(契約) アサーションは、多ければ多いほど良い 一度書いたアサーションは基本的に消さない 詳細は、以下のキーワードで調べてください 事前条件・事後条件・不変条件 ホーア論理 (Hoare logic) 契約プログラミング (Programming (Design) by Contract) 2014-07-14 C プログラミング入門 基幹2 (月4) 22 コンパイルとリンク ソースコード ファイル コンパイル (compile) myprog1.c • • • • savePGM() drawLine() func1() main() 使用するコンパイラに 付属するライブラリ 2014-07-14 リンク (link) オブジェクトファイル myprog1.o 実行可能形式 (executable) myprog1 標準ライブラリ (libc.so) • printf() • malloc() • ... それぞれを行うソフトウェアを、 コンパイラ (compiler), リンカ (linker) という gcc は、これらを総合して実行 するコンパイラドライバである C プログラミング入門 基幹2 (月4) 23 モジュールプログラミング いくつかのプログラムで共通の処理を、ソー スコードから分離する myprog1.c myprog2.c myprog3.c • • • • • • • • • • • • savePGM() drawLine() func1() main() savePGM() loadPGM() func2() main() 同じ関数が複数のプロ グラムに存在する savePGM() loadPGM() drawLine() main() pgm_module.c 共通の処理を抜き出す 2014-07-14 • savePGM() • loadPGM() • drawLine() C プログラミング入門 基幹2 (月4) 24 モジュールプログラミング コンパイル リンク pgm_module.c • savePGM() • loadPGM() • drawLine() pmg_module.o モジュール myprog1.c • func1() • main() myprog1.o myprog1 標準ライブラリ 2014-07-14 C プログラミング入門 基幹2 (月4) 25 モジュール分けしたプログラムのビルド それぞれのソースをコンパイルして、オブ ジェクトファイルを生成 gcc -c -o pgm_module.o pgm_module.c –Wall –Wextra gcc -c -o myprog1.o myprog.c –Wall –Wextra リンク gcc -o myprog1 myprog.o pgm_module.o –Wall –Wextra 2014-07-14 C プログラミング入門 基幹2 (月4) 26 外部リンケージ コンパイル pgm_module.c • savePGM() • loadPGM() • drawLine() myprog1.c • static int func1(void); • main() リンク pmg_module.o 公開される関数 • savePGM • loadPGM • drawLine myprog1.o 公開される関数 • main リンクの対象となる公開され た関数やグローバル変数は外 部リンケージを持つという 関数やグローバル変数は普通 は外部リンケージを持つ myprog1 複数のオブジェクトファイルが同じ名 前の関数や変数を公開している場合、 リンクの結果は未定義である。した がって、最小限のものだけを公開する 必要がある 他のモジュールから使われる 標準ライブラリ ことのない関数, グローバル 変数には static を付ける C プログラミング入門 基幹2 (月4) 2014-07-14 27 モジュールの作成 モジュール分けするために以下のことをする モジュールで公開しない関数に static を付ける モジュールで公開しないグローバル変数に static を付ける モジュールのヘッダファイルとして、公開する関 数のプロトタイプ、公開するグローバル変数の extern 宣言を書く ヘッダファイルにインクルードガードを書く モジュールで自分のヘッダをインクルードする 詳細は、書籍などを参照 2014-07-14 C プログラミング入門 基幹2 (月4) 28
© Copyright 2024 ExpyDoc