M.Hiroi's Home Page
http://www.geocities.jp/m_hiroi/

Linux Programming

お気楽C言語プログラミング超入門

[ Home | Linux ]

WHAT'S NEW


CONTENTS

●番外編


はじめに

『お気楽C言語プログラミング超入門』は M.Hiroi が Linux でC言語を再学習するために作成したページです。入門講座の体裁をとってはいますが、かけ足で進めていくつもりなので、すこし勾配の急な再入門的な内容になる予定です。プログラミング経験がない方にはちょっと難しいかもしれません。M.Hiroi のサビついた腕をどこまでブラッシュアップできるかわかりませんが、興味のある方はお付き合いくださいませ。

●C言語の特徴

C言語は 1972 年 AT&T ベル研究所の D.M.リッチー氏によって UNIX という OS を開発するために作られたプログラミング言語です。OS というシステムソフトウェアを開発するために設計されているので、アセンブラのような低水準に近い操作が可能になっています。このため、C言語は汎用アセンブラとか高級アセンブラといわれることもあります。

ほかの高水準言語とは違い、C言語は配列の範囲やオーバーフローなどのチェックは行っていません。また、「ポインタ」の使い方を誤れば、プログラムは簡単に暴走してしまいます。それでも、コンパクトで高速なマシン語が出力されることと、拡張性や保守性の点ではアセンブラよりも断然優れていることから、C言語は広く普及するようになりました。たいていの環境でC言語を利用することができます。

プログラミング言語はプログラムを実行する方法によって、コンパイラとインタプリタという 2 つの方法に分けることができます。一般に、C言語はコンパイラ型のプログラミング言語に分類されますが、インタプリタ型のC言語もあります。有名なところでは日本 HP の後藤正治さんが開発した C/C++ インタープリタ CINT があります。

Unix 系 OS の場合、標準のCコンパイラに cc がありますが、ほとんどのディストリビューションで GCC (GNU Compiler Collection) が同梱されています。Linux のように、コマンド cc が gcc になっている OS もあります。最近は Clang というコンパイラも使われるようになってきました。Clang - Wikipedia によると、Clang は 『GNUコンパイラコレクション (GCC) を置き換えることのできるコンパイラを提供すること』 を目標にしていて、GCC よりもコンパイルが速く、エラーやワーニングのメッセージがわかりやすいといわれています。

M.Hiroi は Clang に興味があるので、本稿ではCコンパイラに Clang を使ってC言語の学習を進めることにします。Debian 系の OS であれば、次のコマンドで Clang をインストールすることができます。

sudo apt-get intstall clang
mhiroi@mhiroi-VirtualBox:~$ clang --version
Ubuntu clang version 3.5.0-4ubuntu2 (tags/RELEASE_350/final) (based on LLVM 3.5.0)
Target: i386-pc-linux-gnu
Thread model: posix

コマンドは gcc のかわりに clang を使います。なお、Clang は Cygwin でも利用することができます。setup.exe で簡単にインストールすることができるので、Cygwin ユーザーで興味のある方は試してみてください。

●実行ファイルができるまで

C言語でプログラムを作る場合、エディタを使ってソースファイルを作成します。ソースファイルとは、プログラミング言語で記述された命令書のことです。この命令書をコンピュータが理解できるようにマシン語に変換する必要があります。

コンパイラは、ソースファイルを実行ファイルに変換します。一度変換してしまえば、あとは外部コマンドと同様にそのプログラムを実行することができます。それでは、標準的なC言語を例に実行ファイルができるまでの様子を見てみましょう。

          ┌──────────┐      ┌──────────┐
          │ソースファイル abc.c│    ┌┤ヘッダファイル (*.h)│
          └──────────┘    │└──────────┘
                    ↓              ┌┘
              ┌─────┐←───┘ [コンパイラ]
              │コンパイル│---------- cc
              └─────┘           cpp cc1
                    ↓
      ┌─────────────┐
      │アセンブラプログラム abc.s│
      └─────────────┘
                    ↓
              ┌─────┐           [アセンブラ]
              │アセンブル│---------- as
              └─────┘
                    ↓
      ┌─────────────┐
      │オブジェクトファイル abc.o│    ┌─────┐
      └─────────────┘  ┌┤ライブラリ│
                    ↓            ┌─┘└─────┘
                ┌───┐←───┘   [リンカ]
                │リンク│------------ ld
                └───┘
                    ↓
          ┌─────────┐
          │ 実行ファイル abc │
          └─────────┘

     図 : 実行ファイルができるまで

いきなりソースファイルを実行ファイルに変換することはできません。まず、ソースファイルをアセンブラプログラムに変換します。この作業をコンパイルといいます。そして、この作業を行うプログラムをコンパイラといいます。C言語で書かれたプログラムは、Cコンパイラによって変換されます。ほかのプログラミング言語のコンパイラを使うことはできません。

Unix 系 OS で標準的なCコンパイラを使用する場合、ここの処理は cpp と cc1 が担当します。C言語のソースファイルは、拡張子に .c が使われます。ソースファイル abc.c はコンパイラによって abc.s というアセンブラプログラムに変換されます。Unix 系 OS の場合、アセンブルプログラムの拡張子は .s が使用されます。このとき、ソースファイルのほかにも「ヘッダファイル」という複数のファイル ( *.h ) が必要になります。

次に、アセンブラプログラムをオブジェクトファイルに変換します。この作業をアセンブルといい、それを実行するプログラムをアセンブラといいます。Unix 系 OS では as が担当します。

オブジェクトファイルの内容はマシン語なのですが、このままでは実行することができません。オブジェクトファイルを実行ファイルに変換する作業がリンクです。そして、この作業を行うプログラムがリンカと呼ばれます。Unix 系 OS では ld が担当します。オブジェクトファイルの拡張子は .o です。リンク作業は、「ライブラリ」という複数のオブジェクトをまとめたファイルの中から、必要なオブジェクトを取り出し [*1]、abc.o と一緒に結合して abc という実行ファイルを作ります。

このように、実行ファイルに変換するまで、複数のプログラムを使います。いちいち手作業でこれらのプログラムを実行するのでは疲れてしまいますね。そこで、必要なプログラムを順番に呼び出してくれる「コンパイラ・ドライバ」というプログラムが用意されています。これが cc です。GCC であればコマンド gcc を使い、Clang であれば clang を使います。

$ clang -o abc abc.c

上記のように入力するだけで、abc.c は abc という実行ファイルに変換されます。この様子を見ただけでは、アセンブラやリンカが働いていることはわかりません。clang がソースファイルを実行ファイルに変換するように見えますが、今まで説明したように、複数のプログラムが働いているのです。なお、「コンパイルする」というと、一般には、ソースファイルから実行ファイルに変換する作業すべてを指す場合が多いようです。

それでは実際にコンパイルしてみましょう。次のプログラムは画面に hello, world と表示します。

リスト : hello.c

#include <stdio.h>

int main(void)
{
  printf("hello, world\n");
  return 0;
}
mhiroi@mhiroi-VirtualBox:~/clang$ clang -o hello hello.c
mhiroi@mhiroi-VirtualBox:~/clang$ ls
hello  hello.c
mhiroi@mhiroi-VirtualBox:~/clang$ ./hello
hello, world

-o は実行ファイル名を指定するオプションです。-o を省略すると実行ファイル名は a.out になります。

-- note --------
[*1] これは静的ライブラリ (拡張子が .a のファイル) をリンクする場合の話です。Linux では共有ライブラリ (拡張子が .so のファイル) をプログラムの実行時にロードする方法が標準です。

●たらいまわし関数

それでは、お馴染みの「たらいまわし関数」を使って、gcc と clang の実行時間を計測してみましょう。C言語の場合、たらいまわし関数は次のようになります。

リスト : たらいまわし関数

#include <stdio.h>

int tak(int x, int y, int z)
{
  if (x <= y) {
    return z;
  } else {
    return tak(tak(x - 1, y, z), tak(y - 1, z, x), tak(z - 1, x, y));
  }
}

int main(void)
{
  printf("%d\n", tak(24, 12, 0));
  return 0;
}

時間計測はコマンド time を使います。time で時間を計測する場合、プログラムの起動時間も含まれることに注意してください。実行結果は次のようになりました。

mhiroi@mhiroi-VirtualBox:~/clang$ gcc -O2 -o takg tak.c
mhiroi@mhiroi-VirtualBox:~/clang$ clang -O2 -o takc tak.c
mhiroi@mhiroi-VirtualBox:~/clang$ time ./takg
1

real	0m12.335s
user	0m12.308s
sys	0m0.000s
mhiroi@mhiroi-VirtualBox:~/clang$ time ./takc
1

real	0m11.219s
user	0m11.192s
sys	0m0.000s

最適化のオプションはどちらも -O2 を指定しました。Clang のほうが少しだけ速いようです。興味のある方はいろいろ試してみてください。


参考文献・URL

  1. B.W.カーニハン, D.M.リッチー (共著), 石田晴久 (訳), 『プログラミング言語C』, 共立出版, 1981
  2. 平林雅英 (著), 『ANSI C言語辞典』, 技術評論社, 1989
  3. 奥村晴彦,『C言語による最新アルゴリズム事典』, 技術評論社, 1991
  4. Patrick Henry Winston (著), 大鋳史男, 鬼頭繁治 (訳), 『ウィンストンのC』, アジソンウェスレイ, 1995
  5. P.J.プラウガー (著), 福富寛, 門倉明彦, 清水恵介 (訳), 『標準Cライブラリ』, トッパン, 1995
  6. Ravi Sethi (著), 神林靖 (訳), 『プログラミング言語の概念と構造』, アジソンウェスレイ, 1995
  7. 近藤嘉雪, 『Cプログラマのためのアルゴリズムとデータ構造』, ソフトバンク, 1998
  8. C言語 - Wikipedia
  9. 連載:C言語の最新事情を知る, (花井志生さん, Build Insider)

『お気楽C言語プログラミング超入門』の著作権は筆者「広井誠 (Makoto Hiroi) 」が保持します。無断使用や無断転載は禁止いたします。『お気楽C言語プログラミング超入門』で作成したプログラムはフリーソフトウェアとします。ご自由にお使いください。プログラムの改造や配布もご自由にどうぞ。その際は出典を明記してくださるようお願いいたします。

ただし、ドキュメントの内容とプログラムは無保証であり、利用したことにより生じた損害について、作者「広井誠 (Makoto Hiroi) 」 は一切の責任を負いません。また、これらのプログラムを販売することで利益を得るといった商行為は禁止いたします。

Copyright (C) 2015 Makoto Hiroi
All rights reserved.

[ Home | Linux ]