1. プログラミング基礎復習 -- "Hello ESYS" 再び --

【計算機序論2・実習(2012年度)】 目次, 計算機序論2, 授業科目, www.kameda-lab.org 2012/10/20b

本実習の目的は、C言語に慣れてもらうことです。
これまでの授業で最小限のC言語プログラミングはできるようになってきていると思います。

ところで、外国語を勉強するとき、必要なのは才能ではなく練習です。
(ヘミングウェイを目指すなら英語の勉強に加えて才能も必要でしょう。しかし、英語で普通に文章を書けることを目指すだけなら才能など大して要りません。)
日本で生まれ育てば、才能の有無に関係なく、誰でも日本語を話せるようになるでしょう。
(みなさんが米国で生まれ育っていれば、必ず英語だって話せたことでしょう。話すだけなら才能も必要なく時間だけ=練習量さえあればなんとかなるのです。)
C言語も『言語』です。時間さえかけて練習すれば必ず話せる書けるようになります。
(もちろんどの言語でも、個人差はあります。同じ年数生きてきていても日本語の上手下手は個人差あるでしょ?でも喋れない人はいません。)
(Native C speakerなんて人間はちょっと怖いですがそれぐらいを目指すということで。)

ところで、外国語を勉強するとき、必要なのはきちんとした外国語を話せる・書ける先生につくことです。
(ブロークンな英語を喋る知り合いや、文法もよくわかってない友達から英語習ったら、怪しげな英語使いになってしまいます)

C言語もまた「言語」です。
言語である以上、文法があるだけではなく、作法・慣習もあります。

日本語でも、ただ友達と会話する程度なら、誰かに習わなくても友達とつきあっていれば自然に身につきますが、誰と話しても誤解を招かないようなきちんとした日本語を話すためにはそれなりに訓練が必要です。
NHKのアナウンサーが話す日本語と、みなさんが友達と会話しているときの日本語は、同じ日本語でもレベルが違います。

同じことはC言語でも当てはまります。
みなさんはプログラマになる立場(日本語で言えばアナウンサーや新聞記者に相当する立場)ですから、単に書けるだけではなく、正しく簡潔に書けることを目標にしましょう。


01.1. ぞんざいなHello ESYS

まずはC言語プログラミングの復習をしましょう。

計算機序論1までの復習がてら、ウォーミングアップです。
以下のサンプルは「悪い例」です。こんな書き方をしてきた人は反省。
(間違っているわけではないのですが、誤解を招きかねない書き方です)

01-1-HelloESYS-NotSoGood.c

何が悪いのでしょうか?
次のプログラムを見る前に、4つは指摘できるといいですね。

ダウンロードして、このままでコンパイルしてください。コンパイル方法を覚えてますか?
自分なりに修正してください。それをコンパイルし直してください。


01.2 上品なHello ESYS

先のプログラムの書き方は何が悪かったのでしょうか?
次の改善されたプログラムを見てみましょう。

01-2-HelloESYS-Better.c
01-1からの差分

違いがわかりましたか?
(1)"#inlucde <stdio.h>"がない
(2)main()関数にint型を指定していない
(3)main()関数の引数を記述していない
(4)プログラム終了時にmain()関数の返値(int型)を与えていない

コンパイル方法

まず、コマンドラインでのコンパイル方法について、今後は
$ gcc -Wall -o ターゲット名 ソースCファイル
$ gcc -Wall -o 01-2-HelloESYS-Better 01-2-HelloESYS-Better.c

で実行するようにしてください。

-oは習っているかと思いますが、実行ファイル名を"a.out"以外で作ってもらうためのオプションです。

-Wallは習ってますか?
(知らないときはgoogle様に尋ねる?しかし意外に簡単には適切なページは見つからないと思います。)
(「壁って何?」と私も初めて見たときに思いました。)
(まあ当時はgoogle先生はおろかWWWすらなかったのですが‥)
Unixのコマンドは基本的にman ページに説明があります。
(特にOSに近いコマンドの場合は説明が豊富です・・・後でglut関連のような例外も出てきますが。)
(manページとどこかに落ちているwwwページとの違いは、前者が原則として「製作者ないしそれに近い人が書いたドキュメント」であることです。他のはそれを他人が読んで書き直したものにすぎません。例えば、manには最後のほうにAUTHORというセクションがあります。)
その説明をみると、-Wallは"Warning all"の略とわかります。
つまり、文法的に許容できるけど厳密にはおかしい、というところを逐一指摘してくれます。
(微妙におかしい日本語の表現を指摘してくれる先生のようなものですね。)
皆さんは、-Wallをつけても一切Warningが出てこないプログラムを書く習慣をつけてください。
(結局それがプログラムソースを長持ちさせるコツでもあります。経験から断言できます。)
(日本語でも、今風な言い回しで話をして、それを書き留めたり録音しておくと、10年20年経つと「意味不明」と言われることでしょう。)
(丁寧に書いた日本語なら、何年経って聞く人たちのスラングが変わっていても、間違いなく意味が通じます。)
(例:「ヤバくね?」→20年前なら否定の意味。今なら逆の意味。「素晴らしいですよね」と書いておけば昔も今も同じ意味です。)
((なんか話が脱線してるような‥))

printf()

このプログラムではprintf()を使っています。
printf()のように、自分が定義していない関数を使う場合には、必ずそれを作った人が指定している作法に従う必要があります。
printf()のようなプログラミングライブラリの関数についてはmanの3章に説明が集められています。
printf()の作法をman ページで見てみましょう
(ライブラリが何かについては4.2節で学習します)

man ページを読むと、printf()の利用を開始する前に"#include <stdio.h>"を書いておきなさいと指示があることがわかります。
それゆえに、皆さんは"#include <stdio.h>"をファイルの先頭に書かなくてはいけないのです。
(printf()を使わないのなら、"#include <stdio.h>"を書く必要はなくなります。)


01.3 至極丁寧なHello ESYS

少し発展レベルになりますが、より丁寧に記述するなら、下記のように書いておくのがよいでしょう。

01-3-HelloESYS-Full.c
01-2からの差分

C言語のような関数型言語では、原則として全ての関数は返り値を有します。
多くの場合、返値は重要な意味を持っています。
特にその関数が予定通りの作業を実施できたかどうかの目安になる値が返されることが多いです。

唯一の例外はvoid型の関数です。この場合は形無しの返値となります(=返値なし)。
将来、自分で関数を定義することになったら、void型関数は、失敗のしようがない処理や、値を返してもしょうがない状況の時のみ使うように。

printf()は返り値をもつ関数です。どの関数であれ、返り値を持つ関数の返り値には意味があります。無視しない。
printf()のman ページのReturn valueというところを参照すること。)
(どういう値が返ってくるのか承知していて、あえて無視するのなら構いませんが‥)

演算順位は知っていても理解が難しいときがあります。不安な時は括弧を有効活用しましょう。


01.4 使うと便利なマクロ

C言語プリプロセッサによるマクロについてはすでに習っていると聞いてます。
自分で定義して使うのはもちろんOKですが、Cコンパイラの仕様でもとから定義されている便利なマクロもあります。

01-4-HelloESYS-Macros.c

演習

01-04-ex1: 数学のマクロで便利な数値がいろいろと定義されています。
・それはどこで発見できるはずですか?
・実際に5つ以上の数学マクロについて、出典をファイル名・行単位で示しながらその定義を明かにしなさい。


kameda[at]iit.tsukuba.ac.jp