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

【プログラミング序論D】 目次, 講義ページ, 授業科目, www.kameda-lab.org 2017/01/12a

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

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

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

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

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

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


01.01. ぞんざいなHello ESYS

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

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

01-01-HelloESYS-NotSoGood.c

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

ダウンロードして、このままでコンパイルしてください.ターミナル中のコマンドラインからのコンパイル方法を覚えてますか?
プログラムを自分なりに修正してください.それをコンパイルし直してください.

演習

01-01-ex1: 5階計算機システム Ubuntu linux(本授業)において、「ターミナル」とは何を指しますか?

01-01-ex2: このターミナルのようなインタフェースをアルファベット3文字で何と言いますか?その正式名称は何でしょうか?

01-01-ex3: なぜこのテキストばかりのウィンドウを「ターミナル(日本語では端末)」と呼ぶのでしょうか?


01.02 上品なHello ESYS

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

01-02-HelloESYS-Better.c
01-01からの差分

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

「printf()」を例に関数再考

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

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

演習

01-02-ex1: printf()関数を使うときには、include.hが必要になります.
・貴方が実際に使うことになるinclude.hのパス名(場所)を示しなさい.
・そのパスが正しいという根拠を説明しなさい.
・printf()を例に、include.hがその中で何を指定しているか説明しなさい.
・include.hが展開されるのはコンパイル時ですか、リンク時ですか.

01-02-ex2: float変数kに-15.2という数値が入っているとして、printf()関数を使って -15.20%と表示したいとします.
・変数fを引数に採ってprintf()をどう書くべきか示しなさい.
printf()のman ページのどの部分にその書式が載っているか該当部を示しなさい.
 (該当する部分を抜き出して,簡単な日本語訳をつけなさい.1か所とは限りません)


01.03 至極丁寧なHello ESYS

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

01-03-HelloESYS-Full.c
01-02からの差分

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

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

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

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

演習

01-03-ex1: printf()の返値についてです.
・返値の内容を説明しなさい.
・printf()が正常に機能しなかったことを知るにはどのようなプログラムを書けばいいか説明しなさい.
・なぜprintf()の返値を使うC言語プログラムの例がほとんどこの世の中にない(Google先生に聞いても滅多に出てこない)のか,自分なりに説明を試みなさい.

01-03-ex2: C言語の演算子の中で,同じ1つの記号で表されるのに2つの意味を持つものがあります.
・その記号とは何ですか.
・2つの演算の意味をそれぞれ説明しなさい.

01-03-ex3: C言語の演算子の中で,同じ記号を2回繰り返すものがあります.
・そのような演算子を知る限り上げなさい.
・繰り返さない場合と,繰り返す場合のそれぞれの演算の意味を説明しなさい.


01.04 使うと便利なマクロ

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

01-04-HelloESYS-Macros.c

演習

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

01-04-ex2: 本演習ではgccを用いてC言語プログラムのコンパイルを行います.
・使用するgccのバージョンを示しなさい.バージョンを知る方法についても説明すること.
(ヒント:gccにはバージョンを教えてくれる機能があります.)
・そのgccのバージョンが理解するC言語の仕様を示しなさい.
(日本語にも標準語,関西弁,茨城弁があるように,C言語にも様々な違いがあります.人間と違ってコンピュータの世界は融通が利かないので,gccが解釈できるC言語の「方言」は厳密に決まっています)

01-04-ex3: 現在,C言語の最新版はどうなっていますか.
・最新のC言語の仕様が規定された参考文献(URL可)を示し,その特徴を簡単に述べなさい.参考文献は「公式」であることが望まれます.

01-04-ex4: gccのman ページを参照して,このmanページにgcc載っているgccが理解する「方言」がどれぐらいあるか調べなさい.
・そのうちの2つを選んで簡単な説明を加えなさい.


kameda[at]iit.tsukuba.ac.jp