Cygwinでデバッグ

習慣の今昔

コンピュータを取り巻く環境は、短い時間に大きく変化してきています。C言語が生まれて40年ほど、コンピュータの進歩のスピードからすると長大な時間が流れました。この間にC言語も変化してきましたし、プログラミングスタイルというか、思想・哲学も変化しています。ここでは、まずC言語の歴史から知っておきましょう。

C言語の規格3世代

C言語は、UNIX というオペレーティングシステムを記述するために生まれました。1972年前後、アメリカのベル研究所でのことです。考案者のデニス・リッチー (Dennis MacAlistair Ritchie) は、後にブライアン・カーニハン (Brian Wilson Kernighan) とC言語の教科書を出版します。これが『プログラミング言語C』という書籍で、著者2人の頭文字から「K&R」と呼ばれています。言語の教科書としても優れていた同書ですが、付録の言語仕様の説明がしばらく言語の規格書の役割を果たすこととなりました。この頃のC言語が第1世代で、紛らわしいことに、言語規格も「K&R」と呼ばれています。書籍の「K&R」は第2版に改訂されていて今でもバイブルですが、言語規格のほうは今ではさすがに色あせています。

第2世代の言語規格は、当初の考案者の手を離れ、国際標準化機構 (ISO) と米国国内規格協会 (ANSI) が手がけました。1989年から1990年のことです。これが ANSI C または C89 や C90 とも呼ばれるもので、今でもこの規格が主流です。K&R 規格を注意深く拡張しながら、C言語から派生した C++ の関数プロトタイプなどの重要な機能を逆輸入し、一度は死にかけていたC言語の息を吹き返らせることに成功しました。書籍の K&R もこの規格を元に改訂され、前述のように今でもバイブルとして読み続けられています。

バイブルと呼ばれる書籍は、一般に難解で初学者を寄せ付けません。書籍の K&R もご多分に漏れず、「K&R だけで C 言語を理解した」というのは自慢にしかなりませんので、理解できなくても安心して下さい。アセンブラのようなコンピュータ言語に親しんだ人にとっては、理解しやすい構成になっています。

C89 から10年が経ち、C++ も成熟して Java も登場しました。C 言語にも新規格への機運が高まり、その中で策定されたのが第3世代のC言語 C99 です。名前からわかるように 1999年のことで、やはり ISO/ANSI が策定し、C89 と同じく日本工業規格 (JIS) にも取り込まれました。しかしそれから10年が経った現在でもまだ主流とはいい難く、gcc を始めとする新機能の取り込みに意欲的なコンパイラと、Visual Studio のようにそうでないコンパイラの両方が存在します。書籍でも、注釈的に取り上げるものはあっても、全面的に採用したものはまだそれほど見当たりません。少々欲張った拡張が仇になったのかもしれませんが、いくつかの機能については大いに役立つものがありますので、うまく利用したいものです。

C言語の3世代の特徴を列挙すると以下のようになります。

K&R
関数の型チェックなし
ANSI C (C89)
プロトタイプ宣言, void型や列挙型(enum)の導入
C99
1行コメント(//), 変数宣言がブロックの途中でもよい, 可変長配列, 論理型(bool)や複素数型(Complex)の導入

新しい規格の中には、既に当時のコンパイラの独自拡張として広まっていた機能を追認しているものもあります。特に行末までの1行コメント (//) は、C89 の時代からかなり広まっていました。この文章でも、C89 の文脈でも気にせず1行コメントを使っているところもあります。

ANSI C と言えば、昔は紛れもなく C89 のことを指していました。しかし、C99 の策定にも ANSI が関わった結果、ANSI C という表現が C89 だけなのか C99 も含んでいるのか、見分けがつきにくくなりました。(普通は含めないと思います。)もっとも「ANSI C 以降」という表現なら、どちらで解釈しても同じ意味なので、特に問題にならないのかもしれません。

C言語の特徴

このように3世代に渡って進化してきたC言語ですが、一貫した特徴もあります。

つまり、当初のオペレーティングシステムを記述するという目的に見合った、ハードウェア寄りの操作が得意で、実行時の効率が良いという性質がみてとれます。その代わりに、完全なプログラムを書くためには相応のスキルが必要であるという傾向は、改善はされつつも昔から変わっていないというわけです。

例えて言えば、Javaがオートマチック車だとすれば、C言語はマニュアル車どころか、レーシングカーになるでしょう。ギアチェンジが手動なのはもちろん、急ブレーキを小刻みに踏み分けてくれる ABS のような装備もなく、一つ一つの操作がストレートに反映され、間違えた操作はすぐに事故につながります。その代わり、車体も軽く、エンジンの性能を最大限に引き出して高速に走ることができます。いわば、プロのための言語がC言語なのです。

なぜC言語を学ぶのか

このようなプロのための言語を、コンピュータ言語の初学者が習うことが多いのは、言語規模が小さいという特徴が大きく効いているからでしょう。Javaは確かにオートマチックで安全に配慮された言語ですが、オブジェクト指向やスレッドなど、自在にプログラムを書くためには多くの知識が必要とされます。このあたりをうまく隠して少ない知識ですませるように指導するのも一つの方法ですが、単純にC言語を選ぶという戦略にも納得がいきます。もっとも、教える側がC言語に慣れているという側面もそれなりに影響を与えていそうです。

昔はコンパイラ(開発環境)は非常に高価なソフトウェアで、ウン10万円しても当たり前という感覚がありました。当然ながら、大枚をはたいて購入した、1つの言語の1つのコンパイラを使い続けることになりました。今は様々な言語の開発環境が無料で手に入ります。処理内容の得意不得意に応じて言語を気軽に選べるようになりました。

今、最初にC言語を学んでいる人も、これから先はいくつもの言語を使い分けることになるでしょう。最初のとっかかりとして、C言語は悪くない選択ですから、コンピュータ言語一般の習慣を身につけることに主眼を置くことにして、言語特有の機能を深く掘り下げるのはやめておくのが賢明だと思われます。この文章では、似た機能が他の言語ではどう扱われているのか、折りに触れて紹介していきます。

省略の美徳はK&Rの時代のもの

K&R 時代には、コンピュータの能力が今とは比べ物にならないほど貧弱でした。そのため、C言語ソースにも無駄なことは書かないという習慣がありました。具体的には、符号なし整数の型として "unsigned int" とは宣言せずに "unsigned" と int を省略しました。(今でこの習慣は生きています。)こういうものにとどまらず、今なら「5で割り切れない」と判定するのに

if (x % 5 != 0) { ... }

と書きますが、これを短くして

if (x % 5) { ... }

と、比較の != 0 は書かないという流儀がありました。

if の成立条件には != 0 は書いても書かなくても、結果は一緒になります。→比較演算

Java では if (x % 5) { ... } はエラーになります。

同様に、

if (malloc(size) != NULL)

とするところを、

if (malloc(size))

と書く流儀がありました。書かずにすむことは、徹底して書かない、というわけです。

malloc() 関数の動作説明には「エラーの場合、この関数は NULL を返す。」とあるので、NULL との比較式を書くのが素直です。NULL というシンボル(マクロ定数)が0であるのは周知の事実ではありますが、だからといって積極的に省略すべき理由は思いつきません。コンピュータ資源が豊富になった現在では、少ない知識で読み書きできるスタイルを学ぶべきでしょう。

読み易さを根拠にどちらかを勧める人がいるかもしれませんが、たぶん慣れによる影響が大きいと思います。

NULL がどんなコンパイラでも必ず 0 である、と言い切るには、かなりの知識が必要です。→http://www.kouno.jp/home/c_faq/c5.html#5

i++ と ++i の使い分けは職人技

(&&)||(&&)

変数名関数名の長さ制限 6文字 & 8文字


トップ   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS